;;; firejail-mode --- Major mode for editing firejail profiles -*- lexical-binding: t -*- ;;; Commentary: ;;; Code: (defconst firejail-profile-font-lock-keywords (let* ((normal '("quiet" "include" "noblacklist" "nowhitelist" "blacklist" "blacklist-nolog" "bind" "disable-mnt" "keep-config-pulse" "keep-dev-shm" "keep-var-tmp" "mkdir" "mkfile" "noexec" "private" "private-bin" "private-cache" "private-cwd" "private-dev" "private-etc" "private-home" "private-lib" "private-opt" "private-srv" "private-tmp" "read-only" "read-write" "tmpfs" "tracelog" "whitelist" "whitelist-ro" "writable-etc" "writable-run-user" "writable-var" "writable-var-log" "allow-debuggers" "apparmor" "caps" "caps.keep" "caps.drop" "memory-deny-write-execute" "nonewprivs" "noprinters" "noroot" "restrict-namespaces" "seccomp" "seccomp.32" "seccomp.drop" "seccomp.32.drop" "seccomp.keep" "seccomp.32.keep" "protocol" "xephyr-screen" "dbus-system.own" "dbus-system.talk" "dbus-system.see" "dbus-system.call" "dbus-system.broadcast" "dbus-user.own" "dbus-user.talk" "dbus-user.see" "dbus-user.call" "dbus-user.broadcast" "nodbus" "cpu" "nice" "rlimit-as" "rlimit-cpu" "rlimit-fsize" "rlimit-nproc" "rlimit-nofile" "rlimit-sigpending" "timeout" "allusers" "env" "ipc-namespace" "keep-fd" "name" "no3d" "noautopulse" "nodvd" "nogroups" "noinput" "nosound" "notv" "nou2f" "novideo" "machine-id" "defaultgw" "dns" "hostname" "hosts-file" "x11" "dbus-system" "dbus-user" "ip" "ip6" "iprange" "mac" "mtu" "net" "netfilter" "netfilter" "netlock" "netmask" "netns" "veth-name" "deterministic-exit-code" "deterministic-shutdown" "join-or-start")) (take-all-list '("caps.drop")) (take-none-list '("shell" "net")) (comment-rx '("^.*\\(#.*\\)$" 1 font-lock-comment-face)) (dbus-system-user-rx '("^ *\\(\\?[A-Z_]+: +\\)?\ \\(\\(ignore +\\)?\ dbus-\\(system\\|user\\) +\\(none\\|filter\\)?\\)" . 2)) (x11-rx '("^ *\\(?:\\?[A-Z_]+: +\\)?\ \\(\\(?:ignore +\\)?x11 +\\(?:none\\|xephyr\\|xorg\\|xpra\\|xvfb\\)?\\)" . 1)) (ip-ip6-rx '("^ *\\(\\?[A-Z_]+: +\\)?\ \\(\\(ignore +\\)?ip6? +\\(none\\|dhcp\\)\\)" . 2)) (take-all `(,(concat (regexp-opt take-all-list "^ *\\(\\?[A-Z_]+: +\\)?\ \\(\\(ignore +\\)?\\<\\(") "\\>\\)") (2 font-lock-keyword-face) ("\\" nil nil (0 font-lock-keyword-face)))) (take-none `(,(concat (regexp-opt take-none-list "^ *\\(\\?[A-Z_]+: +\\)?\ \\(\\(ignore +\\)?\\<\\(") "\\>\\)") (2 font-lock-keyword-face) ("\\" nil nil (0 font-lock-keyword-face)))) (protocol '("^ *\\(\\?A+: +\\)?\ \\(\\(ignore +\\)?\\\\)" (2 font-lock-keyword-face) ("\\" nil nil (0 font-lock-keyword-face)) ("\\" nil nil (0 font-lock-keyword-face)) ("\\" nil nil (0 font-lock-keyword-face)) ("\\" nil nil (0 font-lock-keyword-face)) ("\\" nil nil (0 font-lock-keyword-face)) ("\\" nil nil (0 font-lock-keyword-face)))) (variable-rx '("\\${[A-Za-z_]*}" 0 font-lock-variable-name-face)) (normal-rx `(,(concat (regexp-opt normal "^ *\\(\\?[A-Z_]+: +\\)?\ \\(\\(ignore +\\)?\\<\\(") "\\>\\)") . 2))) (list comment-rx x11-rx ip-ip6-rx take-all take-none protocol dbus-system-user-rx normal-rx variable-rx '("^ *\\(\\?[A-Z_]+: +\\)?\\(\\\\)" . 2))) "Highlight keywords for `firejail-profile-mode'.") (defvar firejail-profile-syntax-table (let ((syn-table (make-syntax-table))) (modify-syntax-entry ?# "<" syn-table) (modify-syntax-entry ?\n ">" syn-table) syn-table) "Syntax table for `firejail-profile-mode'.") (defconst firejail-profile--keyword-list '("quiet" "include" "noblacklist" "nowhitelist" "blacklist" "blacklist-nolog" "bind" "disable-mnt" "keep-config-pulse" "keep-dev-shm" "keep-var-tmp" "mkdir" "mkfile" "noexec" "private" "private-bin" "private-cache" "private-cwd" "private-dev" "private-etc" "private-home" "private-lib" "private-opt" "private-srv" "private-tmp" "read-only" "read-write" "tmpfs" "tracelog" "whitelist" "whitelist-ro" "writable-etc" "writable-run-user" "writable-var" "writable-var-log" "allow-debuggers" "apparmor" "caps" "caps.keep" "caps.drop" "memory-deny-write-execute" "nonewprivs" "noprinters" "noroot" "restrict-namespaces" "seccomp" "seccomp.32" "seccomp.drop" "seccomp.32.drop" "seccomp.keep" "seccomp.32.keep" "protocol" "xephyr-screen" "dbus-system.own" "dbus-system.talk" "dbus-system.see" "dbus-system.call" "dbus-system.broadcast" "dbus-user.own" "dbus-user.talk" "dbus-user.see" "dbus-user.call" "dbus-user.broadcast" "nodbus" "cpu" "nice" "rlimit-as" "rlimit-cpu" "rlimit-fsize" "rlimit-nproc" "rlimit-nofile" "rlimit-sigpending" "timeout" "allusers" "env" "ipc-namespace" "keep-fd" "name" "no3d" "noautopulse" "nodvd" "nogroups" "noinput" "nosound" "notv" "nou2f" "novideo" "machine-id" "defaultgw" "dns" "hostname" "hosts-file" "x11" "dbus-system" "dbus-user" "ip" "ip6" "iprange" "mac" "mtu" "net" "netfilter" "netfilter" "netlock" "netmask" "netns" "veth-name" "deterministic-exit-code" "ignore" "deterministic-shutdown" "join-or-start" "net" "shell" "protocol") "List of keywords used for `firejail-profile-capf'.") (defun firejail-profile-capf () "Complete the firejail profile directive at point." (if-let ((word-bounds (bounds-of-thing-at-point 'word))) (cl-loop for kwd in firejail-profile--keyword-list with word-at-point = (buffer-substring-no-properties (car word-bounds) (cdr word-bounds)) when (string-prefix-p word-at-point kwd) collect kwd into candidates finally return (list (car word-bounds) (cdr word-bounds) candidates)) (list (point) (point) firejail-profile--keyword-list))) (define-derived-mode firejail-profile-mode prog-mode "Firejail-Profile" "Major mode for editing firejail profiles." (add-to-list (make-local-variable 'completion-at-point-functions) #'firejail-profile-capf) (setq-local font-lock-defaults '(firejail-profile-font-lock-keywords)) (set-syntax-table firejail-profile-syntax-table)) (add-to-list 'auto-mode-alist '("\\.\\(firejail\\|profile\\|local\\)$" . firejail-profile-mode)) (provide 'firejail-mode) ;;; firejail-mode.el ends here