Compare commits

..

47 Commits

Author SHA1 Message Date
Mark Oteiza
8742607120 stop clobbering company-backends
* using add-hook to modify company-backends is bad juju
* there does not appear to be a sensible way for a mode to
  modify company-backends either in the variable docstring or the
  online documentation here

https://company-mode.github.io/manual/Backends.html

  so... we should not modify it.
* document the added effort to use the company backend
* the only additional fanciness to `systemd-company-backend' is that
  it will automatically insert an = after completing a directive, so
  it might be nice to work that into the capf completion somehow and
  trash the company-specific code
2023-01-31 22:02:07 -05:00
Mark Oteiza
964ec9d4e0 happy new year 2023-01-31 21:55:06 -05:00
Mark Oteiza
b6ae63a236 add specifiers (leave obsoleted ones in for now) 2021-02-09 15:52:26 -05:00
Mark Oteiza
0416fe454a drop some unneeded eval-when-compile 2021-02-09 15:52:05 -05:00
Mark Oteiza
20c9d97e24 happy new year 2021-02-09 15:51:44 -05:00
Mark Oteiza
ec8f6cfe9d happy new year 2020-01-30 13:29:39 -05:00
Mark Oteiza
51c148e09a update urls
drop mention of marmalade
2019-12-19 18:04:45 -05:00
Mark Oteiza
9265ef89ff update section lists
there are very many different specialized network sections now.  only
a subset of them have been added here
2019-12-19 18:03:47 -05:00
Mark Oteiza
077aedde23 systemd 244 directives
network stuff is getting split up across a bunch of different sections
which is annoying.  dnssec files are a thing now as well.  finding
a better way to do this would be nice
2019-12-19 18:01:39 -05:00
stardiviner
a9f82b1f8b add systemd-mode company backend buffer locally 2019-11-17 11:14:46 -05:00
Mark Oteiza
c6e06dfa93 happy new year 2019-01-01 04:23:36 -05:00
Lucas Werkmeister
401d71c2dd Add %E, %j, %J, %T, %V specifiers
These specifiers were added in systemd v239.
2018-06-29 17:06:22 -04:00
Lucas Werkmeister
21d50f27d8 Sort specifiers alphabetically
The systemd.unit(5) manpage sorts unit file specifiers alphabetically
since commit systemd/systemd@709f4c472c, and since the order in this
regular expression is even less relevant than in the manpage, let’s just
do the same to make it easy to compare the letter sets between the two.
2018-06-29 17:06:13 -04:00
Lucas Werkmeister
e97f78ee11 Add %S, %C, %L specifiers
These specifiers for the state, cache, and log directory root were added in systemd v236.
2018-04-14 14:11:36 -04:00
Mark Oteiza
228f0b99ca happy new year 2018-01-01 21:03:40 -05:00
Mark Oteiza
22f024fe8f systemd 235 2017-10-06 16:52:43 -04:00
Mark Oteiza
1e7567a997 prepare v1.6 2017-09-18 20:49:18 -04:00
Mark Oteiza
70c762072d add -pkg file to clean target 2017-09-18 20:47:03 -04:00
Mark Oteiza
23c0caf214 extend anchored matches past the current line if \ broken 2017-09-18 07:46:09 -04:00
Mark Oteiza
839094df0e use rx here 2017-09-17 15:37:16 -04:00
Mark Oteiza
16ba942afd rename tests directory 2017-09-17 15:08:47 -04:00
Mark Oteiza
47ae79aed0 Use syntax-propertize and font-lock-extend-region-functions 2017-09-17 14:50:12 -04:00
Mark Oteiza
a3d39214b7 extend multi-line matching to sections and keys 2017-09-11 09:25:09 -04:00
Mark Oteiza
5c9389dae3 move this matcher down with the other ones 2017-09-07 22:04:50 -04:00
Mark Oteiza
b0c1d64d62 add multi-line comment highlighting
between font-lock-keywords, the elisp manual, examples in the emacs
source (sh-mode is one) and the webernets, it is rather difficult to
find a way to properly deal with multi-line construct syntax
highlighting.  this is a way leveraging anchored matching and
jit-lock.
2017-09-07 22:03:17 -04:00
Mark Oteiza
3ff4f0f706 anchor some matchers to follow "=" 2017-09-07 21:59:33 -04:00
Mark Oteiza
a4f409641a moar keywords 2017-09-07 21:57:46 -04:00
Mark Oteiza
995ebbe3d5 add conventional environment variable highlighting 2017-09-03 04:33:37 -04:00
Mark Oteiza
4c0ec1e599 split font-lock-keywords into levels
more importantly, bind systemd-font-lock-keywords to a _symbol_.
this makes hacking font-lock-keywords on the fly a little easier, in
addition to adding to customization/granularity
(info "(elisp) Font Lock Basics")
2017-09-03 04:29:03 -04:00
Mark Oteiza
7bb8f0969d correct syntax? 2017-09-03 03:39:52 -04:00
Mark Oteiza
2c71ec5529 systemd 234.11 2017-07-27 08:04:54 -04:00
Mark Oteiza
9cfd315337 simplify 2017-07-08 18:34:46 -04:00
Mark Oteiza
28601d814f woops 2017-07-08 18:02:26 -04:00
Mark Oteiza
930e82e5fe font lock additional exec prefix 2017-07-07 21:33:41 -04:00
Mark Oteiza
9693935bdd nix extra newline 2017-07-06 22:39:05 -04:00
Mark Oteiza
6884c8f9c6 systemd 233? 2017-07-06 21:12:20 -04:00
Mark Oteiza
4c1b2befd0 bump 2017-02-02 21:44:22 -05:00
Mark Oteiza
a2c60f407a happy belated new year 2017-02-02 21:44:00 -05:00
Mark Oteiza
59ce8ad415 simpler while test 2017-02-02 21:43:08 -05:00
Mark Oteiza
bd94a2cb97 shim in support for nspawn settings files 2017-01-22 20:45:01 -05:00
Mark Oteiza
b561c6bce9 happy new year 2017-01-01 00:03:40 -05:00
Mark Oteiza
fa1277d1cd add reminder
The new regex is not too hard to generate with some set/combinatorics
fun, but perhaps going about this a different way would be better

  (let ((s (delq nil (powerset '("@" "-" "+")))))
    (concat "="
     (regexp-opt
      (mapcar (lambda (ls) (apply #'concat ls))
              (apply #'append (mapcar #'permutations s)))
     "\\(?1:")))
2016-12-02 01:17:46 -05:00
Mark Oteiza
4c073b0c04 missed one 2016-12-02 01:16:12 -05:00
Mark Oteiza
7874a102a5 future flycheck has a checker for units 2016-12-02 01:14:39 -05:00
Mark Oteiza
0a4b6c49d3 shrug 2016-12-02 01:14:06 -05:00
Mark Oteiza
bf7b281cdb nix unneeded arg 2016-12-02 01:11:04 -05:00
Mark Oteiza
f0b29ad130 systemd v232 directives 2016-12-02 00:35:50 -05:00
7 changed files with 491 additions and 83 deletions

View File

@ -1,6 +1,6 @@
SRC = systemd.el
DATA = unit-directives.txt network-directives.txt
DISTFILES := Makefile $(SRC) $(DATA) LICENSE README systemd-pkg.el tests
DATA = unit-directives.txt network-directives.txt nspawn-directives.txt
DISTFILES := Makefile $(SRC) $(DATA) LICENSE README systemd-pkg.el test
VERSION := $(shell awk '/^;; Version:/ {print $$3}' $(SRC))
@ -18,13 +18,13 @@ systemd-pkg.el: $(SRC)
systemd.elc: $(DATA)
check: tests/systemd-tests.el systemd.elc
check: test/systemd-tests.el systemd.elc
@$(EMACS) -Q --batch -L . --eval "(progn \
(load-file \"tests/systemd-tests.el\") \
(load-file \"test/systemd-tests.el\") \
(ert-run-tests-batch-and-exit))"
clean:
$(RM) $(SRC:.el=.elc)
$(RM) $(SRC:.el=.elc) systemd-pkg.el
dist: clean systemd-pkg.el
mkdir systemd-$(VERSION)

3
README
View File

@ -7,8 +7,7 @@ in `systemd.el`.
Installation
------------
Available as the `systemd` package on MELPA <http://melpa.org/> and
marmalade <https://marmalade-repo.org/>.
Available as the `systemd` package on MELPA <https://melpa.org/>.
In Emacs, one can locally install as a package with `make dist` and

View File

@ -1,30 +1,56 @@
ARP
ARPAllTargets
ARPIPTargets
ARPIntervalSec
ARPProxy
ARPValidate
Activate
ActiveSlave
AdActorSystem
AdActorSystemPriority
AdSelect
AdUserPortKey
Address
AddressAutoconfiguration
Advertise
AgeingTimeSec
Alias
AllMulticast
AllSlavesActive
AllowLocalRemote
AllowPortToBeRoot
AllowedIPs
Anonymize
Architecture
AssignToLoopback
AssociatedWith
AutoJoin
AutoNegotiation
BSSID
BindCarrier
BitRate
BitsPerSecond
BlackList
Bond
Bridge
Cache
Broadcast
ClientIdentifier
CombinedChannels
ConfigureWithoutCarrier
CopyDSCP
Cost
CriticalConnection
DHCP
DHCPServer
DNS
DNSDefaultRoute
DNSLifetimeSec
DNSOverTLS
DNSSEC
DNSSECNegativeTrustAnchors
DUIDRawData
DUIDType
DefaultLeaseTimeSec
DefaultPVID
DefaultRouteOnDevice
Description
Destination
DestinationPort
@ -33,40 +59,88 @@ Domains
DownDelaySec
Driver
Duplex
DuplicateAddressDetection
DynamicTransmitLoadBalancing
ERSPANIndex
EgressUntagged
EmitDNS
EmitDomains
EmitLLDP
EmitNTP
EmitRouter
EmitSIP
EmitTimezone
Encapsulation
EncapsulationLimit
EncapsulationType
Encrypt
Endpoint
FDBAgeingSec
FOUDestinationPort
FOUSourcePort
FailOverMACPolicy
FallbackDNS
FallbackNTP
Family
FastLeave
FastOpenNoCookie
FirewallMark
Flags
FlowLabel
FooOverUDP
ForceDHCPv6PDOtherInformation
ForwardDelaySec
From
GVRP
Gateway
GatewayOnLink
GenericProtocolExtension
GenericReceiveOffload
GenericSegmentationOffload
GratuitousARP
Group
GroupForwardMask
GroupPolicyExtension
HairPin
HelloTimeSec
HomeAddress
Host
Hostname
IAID
IPDoNotFragment
IPForward
IPMasquerade
IPProtocol
IPServiceType
IPVLAN
IPv4LLRoute
IPv4ProxyARP
IPv6AcceptRA
IPv6DuplicateAddressDetection
IPv6FlowLabel
IPv6HopLimit
IPv6MTUBytes
IPv6Preference
IPv6PrefixDelegation
IPv6PrivacyExtensions
IPv6ProxyNDP
IPv6ProxyNDPAddress
IPv6RapidDeploymentPrefix
IPv6Token
ISATAP
Id
IgnoreCarrierLoss
IncomingInterface
Independent
InitialAdvertisedReceiveWindow
InitialCongestionWindow
InputKey
InterfaceId
InvertRule
KeepConfiguration
KernelCommandLine
KernelVersion
Key
KeyFile
KeyId
Kind
L2MissNotification
L3MissNotification
@ -74,76 +148,169 @@ LACPTransmitRate
LLDP
LLMNR
Label
LargeReceiveOffload
Layer2SpecificHeader
LearnPacketIntervalSec
Learning
LifetimeSec
LinkLayerAddress
LinkLocalAddressing
ListenPort
Local
LooseBinding
MACAddress
MACAddressPolicy
MACVLAN
MACsec
MIIMonitorSec
MTUBytes
MVRP
MacLearning
ManageTemporaryAddress
Managed
MaxAgeSec
MaxAttempts
MaxLeaseTimeSec
MaximumFDBEntries
Metric
MinLinks
Mode
MultiQueue
Multicast
MulticastDNS
MulticastFlood
MulticastIGMPVersion
MulticastQuerier
MulticastRouter
MulticastSnooping
MulticastToUnicast
NTP
Name
NamePolicy
OneQueue
NeighborSuppression
NetworkEmulatorDelayJitterSec
NetworkEmulatorDelaySec
NetworkEmulatorDuplicateRate
NetworkEmulatorLossRate
NetworkEmulatorPacketLimit
OnLink
OriginalName
OtherChannels
OtherInformation
OutgoingInterface
OutputKey
PVID
PacketInfo
PacketNumber
PacketsPerSlave
Parent
Path
Peer
PeerPort
PeerSessionId
PeerTunnelId
PersistentKeepalive
PoolOffset
PoolSize
Port
PortRange
PreferredLifetime
PreferredLifetimeSec
PreferredSource
Prefix
PrefixDelegationHint
PrefixRoute
PresharedKey
PresharedKeyFile
PrimaryReselectPolicy
PrimarySlave
Priority
PrivateKey
PrivateKeyFile
Property
Protocol
ProxyARP
ProxyARPWiFi
PublicKey
QuickAck
RapidCommit
ReduceARPProxy
Remote
RemoteChecksumRx
RemoteChecksumTx
ReorderHeader
RequestBroadcast
RequestOptions
RequiredForOnline
ResendIGMP
RestartSec
Route
RouteMetric
RouteShortCircuit
RouteTable
RouterLifetimeSec
RouterPreference
RoutesToDNS
RxBufferSize
RxChannels
SSID
STP
SamplePoint
Scope
SendHostname
SendOption
SendRelease
SerializeTunneledPackets
SessionId
Source
SourcePort
TCP6SegmentationOffload
TCPSegmentationOffload
TOS
TTL
TTLPropagate
Table
Timezone
To
TransmitHashPolicy
TripleSampling
Tunnel
UDP6ZeroCheckSumRx
TunnelId
TxBufferSize
TxChannels
Type
TypeOfService
UDP6ZeroChecksumRx
UDP6ZeroChecksumTx
UDPCheckSum
UDPChecksum
UDPSourcePort
UnicastFlood
Unmanaged
UpDelaySec
UseAutonomousPrefix
UseBPDU
UseDNS
UseDomains
UseForEncoding
UseHostname
UseMTU
UseNTP
UseOnLinkPrefix
UseRoutes
UseSIP
UseTimezone
User
UserClass
VLAN
VLANFiltering
VLANId
VNI
VNetHeader
VRF
VXLAN
ValidLifetimeSec
VendorClassIdentifier
Virtualization
WLANInterfaceType
WakeOnLan
Xfrm

38
nspawn-directives.txt Normal file
View File

@ -0,0 +1,38 @@
Boot
Ephemeral
ProcessTwo
Parameters
Environment
User
WorkingDirectory
PivotRoot
Capability
NoNewPrivileges
KillSignal
Personality
MachineID
PrivateUsers
NotifyReady
SystemCallFilter
LimitCPU
OOMScoreAdjust
CPUAffinity
Hostname
ResolvConf
Timezone
LinkJournal
ReadOnly
Volatile
Bind
TemporaryFileSystem
Inaccessible
Overlay
PrivateUsersChown
Private
VirtualEthernet
VirtualEthernetExtra
Interface
MACVLAN
Bridge
Zone
Port

View File

@ -1,9 +1,9 @@
;;; systemd.el --- Major mode for editing systemd units -*- lexical-binding: t -*-
;; Copyright (C) 2014-2016 Mark Oteiza <mvoteiza@udel.edu>
;; Copyright (C) 2014-2023 Mark Oteiza <mvoteiza@udel.edu>
;; Author: Mark Oteiza <mvoteiza@udel.edu>
;; Version: 1.4.1
;; Version: 1.6.1
;; Package-Requires: ((emacs "24.4"))
;; Keywords: tools, unix
@ -24,7 +24,7 @@
;; Major mode for editing systemd units.
;; Similar to `conf-mode' but with added highlighting; e.g. for
;; Similar to `conf-mode' but with enhanced highlighting; e.g. for
;; specifiers and booleans. Employs strict regex for whitespace.
;; Features a facility for browsing documentation: use C-c C-o to open
;; links to documentation in a unit (cf. systemctl help).
@ -33,7 +33,8 @@
;; network configuration. Both a completer for
;; `completion-at-point-functions' and a company backend are provided.
;; The latter can be enabled by adding `company-mode' to
;; `systemd-mode-hook'.
;; `systemd-mode-hook' and adding `systemd-company-backend' to
;; `company-backends'.
;;; Code:
@ -44,9 +45,12 @@
(declare-function company-begin-backend "company")
(declare-function company-grab-symbol "company")
(defvar font-lock-beg)
(defvar font-lock-end)
(defgroup systemd ()
"Major mode for editing systemd units."
:link '(url-link "http://www.freedesktop.org/wiki/Software/systemd/")
:link '(url-link "https://www.freedesktop.org/wiki/Software/systemd/")
:group 'tools)
(defcustom systemd-browse-url-function 'browse-url
@ -73,12 +77,12 @@
(defcustom systemd-mode-hook nil
"Hook run after entering `systemd-mode'."
:type 'hook
:options '(company-mode)
:options '(company-mode flycheck-mode)
:group 'systemd)
(defconst systemd-unit-sections
'("Unit" "Install" "Service")
"Configuration sections for systemd 225.")
"Configuration sections for systemd 244.")
(defconst systemd-unit-directives
(eval-when-compile
@ -91,10 +95,13 @@
"Configuration directives for systemd.")
(defconst systemd-network-sections
'("Match" "Link" "NetDev" "VLAN" "MACVLAN" "MACVTAP" "IPVLAN" "VXLAN"
'("Match" "Link" "NetDev" "VLAN" "MACVLAN" "MACVTAP" "IPVLAN" "IPVTAP" "VXLAN"
"GENEVE" "L2TP" "L2TPsession" "MACsec" "FooOverUDP"
"Tunnel" "Peer" "Tun" "Tap" "Bond" "Network" "Address" "Route" "DHCP"
"Bridge" "BridgeFDB")
"Network configuration sections for systemd 225.")
"Neighbor" "IPv6AddressLabel" "RoutingPolicyRule" "NextHop" "DHCPv4"
"DHCPv6" "IPv6AcceptRA" "DHCPServer" "IPv6Prefix" "CAN"
"Bridge" "BridgeFDB" "BridgeVLAN" "VXCAN" "WireGuard" "WireGuardPeer")
"Network configuration sections for systemd 244 (not exhaustive).")
(defconst systemd-network-directives
(eval-when-compile
@ -106,44 +113,53 @@
(split-string (buffer-string))))
"Network configuration directives for systemd.")
(defconst systemd-nspawn-sections
'("Exec" "Files" "Network")
"Namespace container configuration sections for systemd 244.")
(defconst systemd-nspawn-directives
(eval-when-compile
(with-temp-buffer
(insert-file-contents
(let ((f "nspawn-directives.txt"))
(if (null load-file-name) f
(expand-file-name f (file-name-directory load-file-name)))))
(split-string (buffer-string))))
"Namespace container configuration directives for systemd.")
;;;###autoload
(defconst systemd-autoload-regexp
(eval-when-compile
(rx (+? (any "a-zA-Z0-9-_.@\\")) "."
(or "automount" "busname" "mount" "service" "slice"
"socket" "swap" "target" "timer" "link" "netdev" "network")
string-end))
(rx (+? (any "a-zA-Z0-9-_.@\\")) "."
(or "automount" "busname" "mount" "service" "slice"
"socket" "swap" "target" "timer" "link" "netdev" "network")
string-end)
"Regexp for file buffers in which to autoload `systemd-mode'.")
;;;###autoload
(defconst systemd-tempfn-autoload-regexp
(eval-when-compile
(rx ".#"
(or (and (+? (any "a-zA-Z0-9-_.@\\")) "."
(or "automount" "busname" "mount" "service" "slice"
"socket" "swap" "target" "timer" "link" "netdev" "network"))
"override.conf")
(= 16 (char hex-digit)) string-end))
(rx ".#"
(or (and (+? (any "a-zA-Z0-9-_.@\\")) "."
(or "automount" "busname" "mount" "service" "slice"
"socket" "swap" "target" "timer" "link" "netdev" "network"))
"override.conf")
(= 16 (char hex-digit)) string-end)
"Regexp for temp file buffers in which to autoload `systemd-mode'.")
;;;###autoload
(defconst systemd-dropin-autoload-regexp
(eval-when-compile
(rx "/systemd/" (+? anything) ".d/" (+? (not (any ?/))) ".conf" string-end))
(rx "/systemd/" (+? anything) ".d/" (+? (not (any ?/))) ".conf" string-end)
"Regexp for dropin config file buffers in which to autoload `systemd-mode'.")
(defun systemd-get-value (start)
"Return the value of the key whose value begins at position START.
Lines ending in a backslash are concatenated with the next
according to systemd.unit(5)."
(let ((break "\\\\\n")
end)
(let (end)
(save-excursion
(while (progn (goto-char (1- (line-end-position)))
(looking-at break))
(while (= (char-before (line-end-position)) ?\\)
(forward-line))
(setq end (line-end-position))
(replace-regexp-in-string break " " (buffer-substring start end)))))
(replace-regexp-in-string "\\\\\n" " " (buffer-substring start end)))))
(defun systemd-doc-find ()
"Find the value of the unit's “Documentation” keys.
@ -192,22 +208,27 @@ file, defaulting to the link under point, if any."
(defun systemd-buffer-section-p ()
"Return t if current line begins with \"[\", otherwise nil."
(save-excursion
(beginning-of-line)
(looking-at "\\[")))
(= (char-after (line-beginning-position)) ?\[))
(defun systemd-buffer-network-p ()
"Return non-nil if `buffer-name' has a network-type extension, otherwise nil."
(string-match-p (eval-when-compile
(rx "." (or "link" "netdev" "network") string-end))
(buffer-name)))
(defun systemd-file-network-p (filename)
"Return non-nil if FILENAME has a network-type extension, otherwise nil."
(string-match-p (rx "." (or "link" "netdev" "network") string-end)
filename))
(defun systemd-file-nspawn-p (filename)
"Return non-nil if FILENAME has an nspawn extension, otherwise nil."
(string-match-p (rx ".nspawn" string-end) filename))
(defun systemd-completion-table (&rest _ignore)
"Return a list of completion candidates."
(let ((sectionp (systemd-buffer-section-p)))
(if (systemd-buffer-network-p)
(if sectionp systemd-network-sections systemd-network-directives)
(if sectionp systemd-unit-sections systemd-unit-directives))))
(let ((sectionp (systemd-buffer-section-p))
(name (buffer-name)))
(cond
((systemd-file-nspawn-p name)
(if sectionp systemd-nspawn-sections systemd-nspawn-directives))
((systemd-file-network-p name)
(if sectionp systemd-network-sections systemd-network-directives))
(t (if sectionp systemd-unit-sections systemd-unit-directives)))))
(defun systemd-complete-at-point ()
"Complete the symbol at point."
@ -216,7 +237,7 @@ file, defaulting to the link under point, if any."
(or (cdr bounds) (point))
(completion-table-dynamic #'systemd-completion-table))))
(defun systemd-company-backend (command &optional arg &rest ignored)
(defun systemd-company-backend (command &optional arg &rest _ignored)
"Backend for `company-mode' in `systemd-mode' buffers."
(interactive (list 'interactive))
(pcase command
@ -225,31 +246,130 @@ file, defaulting to the link under point, if any."
(`candidates (all-completions arg (systemd-completion-table nil)))
(`post-completion (if (not (systemd-buffer-section-p)) (insert "=")))))
(defvar systemd-font-lock-keywords
(eval-when-compile
`(("^[[:space:]]*?\\([#;]\\)\\(.*\\)$"
(1 'font-lock-comment-delimiter-face)
(2 'font-lock-comment-face))
("\\\\$" 0 'font-lock-warning-face) ; line break
;; sections
("^\\(\\[\\([[:upper:]][[:alnum:]]+\\|X-.*?\\)\\]\\)"
1 'font-lock-type-face)
;; keys
("^\\([[:upper:]][[:alnum:]]+\\)="
1 'font-lock-keyword-face)
;; boolean arguments
(,(rx "=" (group (or "yes" "true" "on" "0" "no" "false" "off")) eol)
1 'font-lock-constant-face)
;; specifiers
("%[nNpPiIfcrRtuUhsmbHv%]" 0 'font-lock-constant-face)
;; exec prefixes
("=\\(-@\\|@-\\|[@-]\\)" 1 'font-lock-negation-char-face)))
(defun systemd-construct-start-p ()
"Return non-nil if the current line is the first in a multi-line construct."
(let ((flag t))
(save-excursion
(while (and (zerop (forward-line -1))
(eq ?\\ (char-before (line-end-position)))
(skip-chars-forward " \t")
(setq flag (memq (following-char) '(?# ?\;))))))
flag))
(defun systemd-syntax-propertize (start end)
"`systemd-propertize-function' for `systemd-mode' buffers."
(let ((case-fold-search nil))
(goto-char start)
(funcall
(syntax-propertize-rules
("^[ \t]*\\([;#]\\)$?"
(1 (when (systemd-construct-start-p) (string-to-syntax "<")))))
start end)))
(defun systemd-value-extend-region ()
"Return the EOL position of the last line of the construct at point."
(while (and (= (char-before (line-end-position)) ?\\)
(skip-chars-forward " \t")
(not (memq (following-char) '(?# ?\;)))
(zerop (forward-line))))
(line-end-position))
(defun systemd-font-lock-extend-region ()
(goto-char font-lock-beg)
(while (and (zerop (forward-line -1))
(= (char-before (line-end-position)) ?\\)
(skip-chars-forward " \t")
(not (memq (following-char) '(?# ?\;)))))
(setq font-lock-beg (point-marker))
(goto-char font-lock-end)
(setq font-lock-end (systemd-value-extend-region)))
(defmacro define-systemd-matcher (name regexp &optional docstring)
"Define a new function NAME that matches REGEXP in a multi-line construct.
Only returns matches of REGEXP on lines passing `systemd-construct-start-p'."
(declare (debug (symbolp stringp &optional stringp))
(indent 2) (doc-string 3))
`(defun ,name (limit)
,docstring
(let (match)
(while (and (setq match (re-search-forward ,regexp limit t))
(not (systemd-construct-start-p))))
match)))
(define-systemd-matcher systemd-section-matcher
"^\\(\\[\\([[:upper:]][[:alnum:]]+\\|X-.*?\\)\\]\\)"
"Matcher for section titles.")
(define-systemd-matcher systemd-key-matcher "^\\([[:upper:]][[:alnum:]]+\\)="
"Matcher for keys (unit directives).")
(defun systemd-exec-prefix-anchored-matcher (limit)
"Matcher for the exec prefix in anchored font-lock rule.
See `font-lock-keywords' and (info \"(elisp) Search-based Fontification\")."
(let ((pos (car (match-data)))
(prefixes '(?- ?@ ?+))
char end res)
(while (and (memq (setq char (following-char)) prefixes)
(< (point) limit))
(forward-char)
(setq prefixes (remq char prefixes))
(setq end (point-marker)))
(when end
(prog1 (setq res (list (1+ pos) end))
(set-match-data res)))))
(defconst systemd-font-lock-keywords-1
'((systemd-section-matcher 1 'font-lock-type-face)
(systemd-key-matcher 1 'font-lock-keyword-face))
"Minimal expressions to highlight in `systemd-mode'.")
(defconst systemd-font-lock-keywords-2
`(,@systemd-font-lock-keywords-1
("\\\\$" 0 'font-lock-warning-face) ; line break
;; boolean arguments
(,(rx "=" (group (or "yes" "true" "on" "0" "no" "false" "off")) eol)
1 'font-lock-constant-face)
("="
;; exec prefixes
(systemd-exec-prefix-anchored-matcher
nil nil (0 'font-lock-negation-char-face))
;; environment variables
("\\$[A-Z_]+\\>"
(systemd-value-extend-region) nil (0 'font-lock-variable-name-face))
;; specifiers
("%[abBCEfgGhHiIjJlLmnNopPrRsStTuUvVw%]"
(systemd-value-extend-region) nil (0 'font-lock-constant-face))))
"Extended expressions to highlight in `systemd-mode'.")
(defconst systemd-font-lock-keywords-3
`(,@systemd-font-lock-keywords-2
("^Type=\\(simple\\|forking\\|oneshot\\|dbus\\|notify\\|idle\\)$"
1 'font-lock-builtin-face)
(,(rx bol "Restart="
(group (or "no" "on-success" "on-failure"
"on-abnormal" "on-watchdog" "on-abort" "always"))
eol)
1 'font-lock-builtin-face)
("^KillMode=\\(control-group\\|process\\|mixed\\|none\\)$"
1 'font-lock-builtin-face)
(,(rx bol "KillSignal="
(group
(or "SIGHUP" "SIGINT" "SIGQUIT" "SIGILL" "SIGABRT" "SIGFPE" "SIGKILL"
"SIGSEGV" "SIGPIPE" "SIGALRM" "SIGTERM" "SIGUSR1" "SIGUSR2"
"SIGCHLD" "SIGCONT" "SIGSTOP" "SIGTSTP" "SIGTTIN" "SIGTTOU"))
eol)
1 'font-lock-constant-face))
"Flamboyant expressions to highlight in `systemd-mode'.")
(defvar systemd-font-lock-keywords 'systemd-font-lock-keywords-2
"Default expressions to highlight in `systemd-mode'.
See systemd.unit(5) for details on unit file syntax.")
(defvar systemd-mode-syntax-table
(let ((table (make-syntax-table)))
(modify-syntax-entry ?\% "\\" table)
(modify-syntax-entry ?% "/" table)
(modify-syntax-entry ?$ "'" table)
(modify-syntax-entry ?\; "." table)
table)
"Syntax table used in `systemd-mode' buffers.")
@ -268,6 +388,7 @@ See systemd.unit(5) for details on unit file syntax.")
["Open systemd.directives(7)" systemd-doc-directives
:help "Index of configuration directives"]))
;;;###autoload (add-to-list 'auto-mode-alist '("\\.nspawn\\'" . systemd-mode))
;;;###autoload (add-to-list 'auto-mode-alist `(,systemd-autoload-regexp . systemd-mode))
;;;###autoload (add-to-list 'auto-mode-alist `(,systemd-tempfn-autoload-regexp . systemd-mode))
;;;###autoload (add-to-list 'auto-mode-alist `(,systemd-dropin-autoload-regexp . systemd-mode))
@ -275,7 +396,7 @@ See systemd.unit(5) for details on unit file syntax.")
;;;###autoload
(define-derived-mode systemd-mode conf-mode "Systemd"
"Major mode for editing systemd unit files.
See http://www.freedesktop.org/wiki/Software/systemd/ for more
See https://www.freedesktop.org/wiki/Software/systemd/ for more
information about systemd.
In addition to any hooks its parent mode might have run, this
@ -285,9 +406,16 @@ Key bindings:
\\{systemd-mode-map}"
(set-keymap-parent systemd-mode-map nil)
(conf-mode-initialize systemd-comment-start)
(add-hook 'company-backends #'systemd-company-backend nil)
(setq-local auto-fill-inhibit-regexp "^[ \t]*?[^;#]")
(add-hook 'completion-at-point-functions #'systemd-complete-at-point nil t)
(setq font-lock-defaults '(systemd-font-lock-keywords t)))
(add-hook 'font-lock-extend-region-functions
'systemd-font-lock-extend-region nil t)
(setq-local syntax-propertize-function #'systemd-syntax-propertize)
(setq font-lock-defaults
'((systemd-font-lock-keywords
systemd-font-lock-keywords-1
systemd-font-lock-keywords-2
systemd-font-lock-keywords-3))))
(provide 'systemd)

View File

@ -1,6 +1,6 @@
;;; systemd-tests.el --- Tests for systemd.el -*- lexical-binding: t -*-
;; Copyright (C) 2016 Mark Oteiza <mvoteiza@udel.edu>
;; Copyright (C) 2016-2020 Mark Oteiza <mvoteiza@udel.edu>
;; Author: Mark Oteiza <mvoteiza@udel.edu>
@ -83,4 +83,3 @@ only if in an appropriately named parent directory."
(provide 'systemd-tests)
;;; systemd-tests.el ends here

View File

@ -3,18 +3,23 @@ AccuracySec
After
Alias
AllowIsolate
AllowedCPUs
AllowedMemoryNodes
Also
AmbientCapabilities
AppArmorProfile
AssertACPower
AssertArchitecture
AssertCapability
AssertControlGroupController
AssertDirectoryNotEmpty
AssertFileIsExecutable
AssertFileNotEmpty
AssertFirstBoot
AssertGroup
AssertHost
AssertKernelCommandLine
AssertKernelVersion
AssertNeedsUpdate
AssertPathExists
AssertPathExistsGlob
@ -23,10 +28,13 @@ AssertPathIsMountPoint
AssertPathIsReadWrite
AssertPathIsSymbolicLink
AssertSecurity
AssertUser
AssertVirtualization
Backlog
Before
BindIPv6Only
BindPaths
BindReadOnlyPaths
BindToDevice
BindsTo
BlockIOAccounting
@ -39,20 +47,30 @@ BusName
CPUAccounting
CPUAffinity
CPUQuota
CPUQuotaPeriodSec
CPUSchedulingPolicy
CPUSchedulingPriority
CPUSchedulingResetOnFork
CPUShares
CPUWeight
CacheDirectory
CacheDirectoryMode
CapabilityBoundingSet
CollectMode
ConditionACPower
ConditionArchitecture
ConditionCPUs
ConditionCapability
ConditionControlGroupController
ConditionDirectoryNotEmpty
ConditionFileIsExecutable
ConditionFileNotEmpty
ConditionFirstBoot
ConditionGroup
ConditionHost
ConditionKernelCommandLine
ConditionKernelVersion
ConditionMemory
ConditionNeedsUpdate
ConditionPathExists
ConditionPathExistsGlob
@ -61,7 +79,10 @@ ConditionPathIsMountPoint
ConditionPathIsReadWrite
ConditionPathIsSymbolicLink
ConditionSecurity
ConditionUser
ConditionVirtualization
ConfigurationDirectory
ConfigurationDirectoryMode
Conflicts
DefaultDependencies
DefaultInstance
@ -72,9 +93,12 @@ DeviceAllow
DevicePolicy
DirectoryMode
DirectoryNotEmpty
DisableControllers
Documentation
DynamicUser
Environment
EnvironmentFile
ExecCondition
ExecReload
ExecStart
ExecStartPost
@ -83,12 +107,16 @@ ExecStop
ExecStopPost
ExecStopPre
FailureAction
FailureActionExitStatus
FileDescriptorName
FileDescriptorStoreMax
FinalKillSignal
ForceUnmount
FreeBind
Group
GuessMainPID
IOAccounting
IODeviceLatencyTargetSec
IODeviceWeight
IOReadBandwidthMax
IOReadIOPSMax
@ -97,11 +125,17 @@ IOSchedulingPriority
IOWeight
IOWriteBandwidthMax
IOWriteIOPSMax
IPAccounting
IPAddressAllow
IPAddressDeny
IPEgressFilterPath
IPIngressFilterPath
IPTOS
IPTTL
IgnoreOnIsolate
IgnoreSIGPIPE
InaccessiblePaths
JobRunningTimeoutSec
JobTimeoutAction
JobTimeoutRebootArgument
JobTimeoutSec
@ -110,8 +144,10 @@ KeepAlive
KeepAliveIntervalSec
KeepAliveProbes
KeepAliveTimeSec
KeyringMode
KillMode
KillSignal
LazyUnmount
LimitAS
LimitCORE
LimitCPU
@ -136,30 +172,47 @@ ListenSequentialPacket
ListenSpecial
ListenStream
ListenUSBFunction
LockPersonality
LogExtraFields
LogLevelMax
LogRateLimitBurst
LogRateLimitIntervalSec
LogsDirectory
LogsDirectoryMode
MakeDirectory
Mark
MaxConnections
MaxConnectionsPerSource
MemoryAccounting
MemoryDenyWriteExecute
MemoryHigh
MemoryLimit
MemoryLow
MemoryMax
MemoryMin
MemorySwapMax
MessageQueueMaxMessages
MessageQueueMessageSize
MountAPIVFS
MountFlags
NUMAMask
NUMAPolicy
NetworkNamespacePath
Nice
NoDelay
NoNewPrivileges
NonBlocking
NotifyAccess
OOMPolicy
OOMScoreAdjust
OnActiveSec
OnBootSec
OnCalendar
OnClockChange
OnFailure
OnFailureJobMode
OnStartupSec
OnTimezoneChange
OnUnitActiveSec
OnUnitInactiveSec
Options
@ -173,16 +226,22 @@ PathChanged
PathExists
PathExistsGlob
PathModified
PermissionsStartOnly
Persistent
Personality
PipeSize
Priority
PrivateDevices
PrivateMounts
PrivateNetwork
PrivateTmp
PrivateUsers
PropagatesReloadTo
ProtectControlGroups
ProtectHome
ProtectHostname
ProtectKernelLogs
ProtectKernelModules
ProtectKernelTunables
ProtectSystem
RandomizedDelaySec
ReadOnlyPaths
@ -194,6 +253,7 @@ RefuseManualStop
ReloadPropagatedFrom
RemainAfterElapse
RemainAfterExit
RemoveIPC
RemoveOnStop
RequiredBy
Requires
@ -201,15 +261,20 @@ RequiresMountsFor
Requisite
Restart
RestartForceExitStatus
RestartKillSignal
RestartPreventExitStatus
RestartSec
RestrictAddressFamilies
RestrictNamespaces
RestrictRealtime
RestrictSUIDSGID
ReusePort
RootDirectory
RootDirectoryStartOnly
RootImage
RuntimeDirectory
RuntimeDirectoryMode
RuntimeDirectoryPreserve
RuntimeMaxSec
SELinuxContext
SELinuxContextFromNet
@ -232,14 +297,21 @@ Sockets
SourcePath
StandardError
StandardInput
StandardInputData
StandardInputText
StandardOutput
StartLimitAction
StartLimitBurst
StartLimitIntervalSec
StartupBlockIOWeight
StartupCPUShares
StartupCPUWeight
StartupIOWeight
StateDirectory
StateDirectoryMode
StopWhenUnneeded
SuccessAction
SuccessActionExitStatus
SuccessExitStatus
SupplementaryGroups
Symlinks
@ -257,6 +329,9 @@ TTYVHangup
TTYVTDisallocate
TasksAccounting
TasksMax
TemporaryFileSystem
TimeoutAbortSec
TimeoutCleanSec
TimeoutIdleSec
TimeoutSec
TimeoutStartSec
@ -270,6 +345,7 @@ UMask
USBFunctionDescriptors
USBFunctionStrings
Unit
UnsetEnvironment
User
UtmpIdentifier
UtmpMode
@ -277,6 +353,7 @@ WakeSystem
WantedBy
Wants
WatchdogSec
WatchdogSignal
What
Where
WorkingDirectory