1 ;;; systemd-mode.el --- Major modes for systemd unit files -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2016 Free Software Foundation, Inc.
5 ;; Author: Mario Lang <mlang@delysid.org>
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
23 ;; * Add support for systemd-networkd .link and .network files.
29 (defvar systemd-unit-font-lock-keywords
31 ("^[ \t]*\\[\\(Unit\\|Service\\)\\]"
32 1 'font-lock-type-face)
34 ("^[ \t]*\\(.+?\\)[ \t]*="
35 1 'font-lock-variable-name-face))
36 "Keywords to highlight in Conf mode.")
38 (defvar-local systemd-unit-mode-sections '("Unit" "Install"))
40 (defvar systemd-unit-mode-map
41 (let ((map (make-sparse-keymap)))
42 (define-key map "\t" #'completion-at-point)
45 (define-derived-mode systemd-unit-mode conf-unix-mode "Systemd-Unit"
46 (conf-mode-initialize "#" systemd-unit-font-lock-keywords)
47 (add-hook 'completion-at-point-functions #'systemd-mode-completion-at-point
49 (setq-local completion-ignore-case t))
52 (define-derived-mode systemd-automount-mode systemd-unit-mode "Systemd-AutoMount"
53 "Major mode for editing systemd .automount unit files"
54 (add-to-list 'systemd-unit-mode-sections "AutoMount"))
57 (define-derived-mode systemd-mount-mode systemd-unit-mode "Systemd-Mount"
58 "Major mode for editing systemd .mount unit files"
59 (add-to-list 'systemd-unit-mode-sections "Mount"))
62 (define-derived-mode systemd-path-mode systemd-unit-mode "Systemd-Path"
63 "Major mode for editing systemd .path unit files"
64 (add-to-list 'systemd-unit-mode-sections "Path"))
67 (define-derived-mode systemd-service-mode systemd-unit-mode "Systemd-Service"
68 "Major mode for editing systemd .service unit files."
69 (add-to-list 'systemd-unit-mode-sections "Service"))
72 (define-derived-mode systemd-socket-mode systemd-unit-mode "Systemd-Socket"
73 "Major mode for editing systemd .socket unit files."
74 (add-to-list 'systemd-unit-mode-sections "Socket"))
77 (define-derived-mode systemd-swap-mode systemd-unit-mode "Systemd-Swap"
78 "Major mode for editing systemd .swap unit files."
79 (add-to-list 'systemd-unit-mode-sections "Swap"))
82 (define-derived-mode systemd-timer-mode systemd-unit-mode "Systemd-Timer"
83 "Major mode for editing systemd .timer unit files."
84 (add-to-list 'systemd-unit-mode-sections "Timer"))
86 (defvar systemd-mode-section-keywords-alist
88 "Where" "DirectoryMode" "TimeoutIdleSec")
91 "What" "Where" "Type" "Options" "SloppyOptions" "DirectoryMode"
94 "PathExists" "PathExistsGlob" "PathChanged" "PathModified"
95 "DirectoryNotEmpty" "Unit" "MakeDirectory" "DirectoryMode")
97 "Type" "RemainAfterExit" "GuessMainPID" "PIDFile" "BusName"
98 "ExecStart" "ExecStartPre" "ExecStartPost" "ExecReload"
99 "ExecStop" "ExecStopPost" "RestartSec" "TimeoutStartSec"
100 "TimeoutStopSec" "TimeoutSec" "RuntimeMaxSec" "WatchdogSec"
101 "Restart" "SuccessExitStatus" "RestartPreventExitStatus"
102 "RestartForceExitStatus" "PermissionsStartOnly"
103 "RootDirectoryStartOnly" "NonBlocking" "NotifyAccess" "Sockets"
104 "FailureAction" "FileDescriptorStoreMax" "USBFunctionDescriptors"
105 "USBFunctionStrings")
108 "ListenStream" "ListenDatagram" "ListenSequentialPacket"
109 "ListenFIFO" "ListenSpecial" "ListenNetlink" "ListenMessageQueue"
110 "ListenUSBFunction" "SocketProtocol" "BindIPv6Only"
111 "Backlog" "BindToDevice" "SocketUser" "SocketGroup"
112 "SocketMode" "DirectoryMode" "Accept" "Writable" "MaxConnections"
113 "KeepAlive" "KeepAliveTimeSec" "KeepAliveIntervalSec"
114 "KeepAliveProbes" "NoDelay" "Priority" "DeferAcceptSec"
115 "ReceiveBuffer" "SendBuffer" "IPTOS" "IPTTL" "Mark" "ReusePort"
116 "SmackLabel" "SmackLabelIPIn" "SmackLabelIPOut"
117 "SELinuxContextFromNet" "PipeSize" "MessageQueueMaxMessages"
118 "MessageQueueMessageSize" "FreeBind" "Transparent" "Broadcast"
119 "PassCredentials" "PassSecurity" "TCPCongestion" "ExecStartPre"
120 "ExecStartPost" "ExecStopPre" "ExecStopPost" "TimeoutSec"
121 "Service" "RemoveOnStop" "Symlinks" "FileDescriptorName"
122 "TriggerLimitIntervalSec" "TriggerLimitBurst")
124 "What" "Priority" "Options" "TimeoutSec")
127 "OnActiveSec" "OnBootSec" "OnStartupSec" "OnUnitActiveSec"
128 "OnUnitInactiveSec" "OnCalendar" "AccuracySec" "RandomizedDelaySec"
129 "Unit" "Persistent" "WakeSystem" "RemainAfterElapse")
131 "Description" "Documentation" "Requires" "Requisite" "Wants" "BindsTo"
132 "PartOf" "Conflicts" "Before" "After" "OnFailure" "PropagatesReloadTo"
133 "ReloadPropagatedFrom" "JoinsNamespaceOf" "RequiresMountsFor"
134 "OnFailureJobMode" "IgnoreOnIsolate" "StopWhenUnneeded" "RefuseManualStart"
135 "RefuseManualStop" "AllowIsolate" "DefaultDependencies"
136 "JobTimeoutSec" "JobTimeoutAction" "JobTimeoutRebootArgument"
137 "StartLimitIntervalSec" "StartLimitBurst"
138 "StartLimitAction" "RebootArgument"
139 "ConditionArchitecture" "ConditionVirtualization" "ConditionHost"
140 "ConditionKernelCommandLine" "ConditionSecurity" "ConditionCapability"
141 "ConditionACPower" "ConditionNeedsUpdate" "ConditionFirstBoot"
142 "ConditionPathExists" "ConditionPathExistsGlob" "ConditionPathIsDirectory"
143 "ConditionPathIsSymbolicLink" "ConditionPathIsMountPoint"
144 "ConditionPathIsReadWrite" "ConditionDirectoryNotEmpty"
145 "ConditionFileNotEmpty" "ConditionFileIsExecutable"
146 "AssertArchitecture" "AssertVirtualization" "AssertHost"
147 "AssertKernelCommandLine" "AssertSecurity" "AssertCapability"
148 "AssertACPower" "AssertNeedsUpdate" "AssertFirstBoot" "AssertPathExists"
149 "AssertPathExistsGlob" "AssertPathIsDirectory" "AssertPathIsSymbolicLink"
150 "AssertPathIsMountPoint" "AssertPathIsReadWrite" "AssertDirectoryNotEmpty"
151 "AssertFileNotEmpty" "AssertFileIsExecutable"
154 "Alias" "WantedBy" "RequiredBy" "Also" "DefaultInstance")))
156 (defvar systemd-mode-section-regexp "^[ \t]*\\[\\([[:alpha:]]+\\)]")
158 (defun systemd-mode-completion-at-point ()
159 (if (save-excursion (re-search-backward systemd-mode-section-regexp nil t))
160 (let ((section (match-string-no-properties 1)))
161 (if (member-ignore-case section systemd-unit-mode-sections)
162 (let ((keywords (cdr (assoc-string
163 section systemd-mode-section-keywords-alist t))))
167 (skip-chars-backward "[:alpha:]")
168 (let ((start (point)))
169 (skip-chars-backward " \t")
170 (when (eq (line-beginning-position) (point))
171 (list start end (mapcar (lambda (str) (concat str "="))
173 (display-warning major-mode
174 (format "Unexpected section [%s]." section)
179 (add-to-list 'auto-mode-alist '("\\.automount\\'" . systemd-automount-mode))
182 (add-to-list 'auto-mode-alist '("\\.mount\\'" . systemd-mount-mode))
185 (add-to-list 'auto-mode-alist '("\\.path\\'" . systemd-path-mode))
188 (add-to-list 'auto-mode-alist '("\\.service\\'" . systemd-service-mode))
191 (add-to-list 'auto-mode-alist '("\\.socket\\'" . systemd-socket-mode))
194 (add-to-list 'auto-mode-alist '("\\.swap\\'" . systemd-swap-mode))
197 (add-to-list 'auto-mode-alist '("\\.timer\\'" . systemd-timer-mode))
199 (provide 'systemd-mode)
200 ;;; systemd-mode.el ends here