summaryrefslogtreecommitdiff
path: root/slang-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'slang-mode.el')
-rw-r--r--slang-mode.el293
1 files changed, 293 insertions, 0 deletions
diff --git a/slang-mode.el b/slang-mode.el
new file mode 100644
index 0000000..2e08371
--- /dev/null
+++ b/slang-mode.el
@@ -0,0 +1,293 @@
1;;; -*- lexical-binding: t; -*-
2;;; slang-lsp.el --- Major mode for Slang shader files
3
4;; Author: Michael Ghaben <michaelghaben@gmail.com>
5;; Version: 0.0.1
6;; Package-Requires: ((emacs "28.1") (eglot "1.19"))
7;; Keywords: slang shaders vulkan opengl spir-v
8
9;;; Code:
10(require 'cc-mode)
11(require 'font-lock)
12
13(defgroup slang nil
14 "Major mode for Slang shader files."
15 :group 'language
16 :prefix "slang-")
17
18(defcustom slang-indent-offset 4
19 "Indentation offset for Slang code."
20 :type 'integer
21 :group 'slang)
22
23;; Syntax table
24(defvar slang-mode-syntax-table
25 (let ((table (make-syntax-table)))
26 ;; C-style comments
27 (modify-syntax-entry ?/ ". 124b" table)
28 (modify-syntax-entry ?* ". 23" table)
29 (modify-syntax-entry ?\n "> b" table)
30
31 ;; Strings
32 (modify-syntax-entry ?\" "\"" table)
33 (modify-syntax-entry ?\' "\"" table)
34
35 ;; Operators and punctuation
36 (modify-syntax-entry ?+ "." table)
37 (modify-syntax-entry ?- "." table)
38 (modify-syntax-entry ?% "." table)
39 (modify-syntax-entry ?< "." table)
40 (modify-syntax-entry ?> "." table)
41 (modify-syntax-entry ?& "." table)
42 (modify-syntax-entry ?| "." table)
43 (modify-syntax-entry ?= "." table)
44 (modify-syntax-entry ?! "." table)
45
46 ;; Underscore as word constituent
47 (modify-syntax-entry ?_ "w" table)
48
49 table)
50 "Syntax table for Slang mode.")
51
52;; Font lock keywords - comprehensive Slang language support
53(defconst slang-font-lock-keywords
54 (list
55 ;; Preprocessor directives
56 '("^[ \t]*#.*$" . 'font-lock-preprocessor-face)
57
58 ;; Attributes (shader annotations)
59 '("\\[\\([^]]+\\)\\]" . 'font-lock-preprocessor-face)
60
61 ;; Keywords - core language
62 `(,(regexp-opt '("break" "case" "continue" "default" "do" "else" "for"
63 "if" "return" "switch" "while" "goto"
64 "const" "static" "uniform" "varying" "in" "out" "inout"
65 "public" "private" "internal" "extern"
66 "true" "false" "null" "none")
67 'words)
68 . 'font-lock-keyword-face)
69
70 ;; Keywords - Slang-specific
71 `(,(regexp-opt '("interface" "struct" "enum" "class" "namespace" "module"
72 "import" "export" "using" "typealias" "associatedtype"
73 "extension" "where" "let" "var" "property" "subscript"
74 "init" "__init" "deinit" "__deinit" "this" "This" "Self"
75 "super" "throws" "try" "catch" "finally"
76 "is" "as" "sizeof" "alignof" "offsetof"
77 "expand" "each" "repeat" "unroll" "loop"
78 "target" "version" "profile" "stage" "binding"
79 "set" "get" "implements" "extends")
80 'words)
81 . 'font-lock-keyword-face)
82
83 ;; Storage class keywords
84 `(,(regexp-opt '("typedef" "register" "auto" "volatile" "inline"
85 "virtual" "abstract" "override" "final" "sealed")
86 'words)
87 . 'font-lock-keyword-face)
88
89 ;; Built-in scalar types
90 `(,(regexp-opt '("void" "bool" "int" "uint" "float" "double" "half"
91 "int8_t" "uint8_t" "int16_t" "uint16_t"
92 "int32_t" "uint32_t" "int64_t" "uint64_t"
93 "float16_t" "float32_t" "float64_t"
94 "string" "StringLiteral")
95 'words)
96 . 'font-lock-type-face)
97
98 ;; Vector and matrix types
99 '("\\b\\(bool\\|int\\|uint\\|float\\|double\\|half\\)\\([1-4]\\)\\b" . 'font-lock-type-face)
100 '("\\b\\(bool\\|int\\|uint\\|float\\|double\\|half\\)\\([1-4]\\)x\\([1-4]\\)\\b" . 'font-lock-type-face)
101
102 ;; Texture and buffer types
103 `(,(regexp-opt '("Texture1D" "Texture2D" "Texture3D" "TextureCube"
104 "Texture1DArray" "Texture2DArray" "TextureCubeArray"
105 "Texture2DMS" "Texture2DMSArray"
106 "RWTexture1D" "RWTexture2D" "RWTexture3D"
107 "RWTexture1DArray" "RWTexture2DArray"
108 "Buffer" "RWBuffer" "StructuredBuffer" "RWStructuredBuffer"
109 "ByteAddressBuffer" "RWByteAddressBuffer"
110 "ConstantBuffer" "TextureBuffer" "RWTextureBuffer"
111 "AppendStructuredBuffer" "ConsumeStructuredBuffer"
112 "SamplerState" "SamplerComparisonState"
113 "RasterizerOrderedBuffer" "RasterizerOrderedStructuredBuffer"
114 "RasterizerOrderedTexture1D" "RasterizerOrderedTexture2D"
115 "RasterizerOrderedTexture3D")
116 'words)
117 . 'font-lock-type-face)
118
119 ;; Built-in interfaces
120 `(,(regexp-opt '("IArithmetic" "ILogical" "IComparable" "IFloat"
121 "IInteger" "ISigned" "IUnsigned" "INumeric"
122 "IDifferentiable" "ITexture" "IResource")
123 'words)
124 . 'font-lock-type-face)
125
126 ;; HLSL semantics and system values
127 `(,(regexp-opt '("SV_Position" "SV_Target" "SV_Depth" "SV_Coverage"
128 "SV_VertexID" "SV_InstanceID" "SV_PrimitiveID"
129 "SV_DispatchThreadID" "SV_GroupID" "SV_GroupThreadID"
130 "SV_GroupIndex" "SV_DomainLocation" "SV_InsideTessFactor"
131 "SV_TessFactor" "SV_OutputControlPointID" "SV_GSInstanceID"
132 "POSITION" "NORMAL" "TANGENT" "BINORMAL" "COLOR"
133 "TEXCOORD0" "TEXCOORD1" "TEXCOORD2" "TEXCOORD3"
134 "TEXCOORD4" "TEXCOORD5" "TEXCOORD6" "TEXCOORD7"
135 "BLENDWEIGHT" "BLENDINDICES" "PSIZE" "FOG")
136 'words)
137 . 'font-lock-constant-face)
138
139 ;; Boolean constants
140 `(,(regexp-opt '("true" "false") 'words) . 'font-lock-constant-face)
141
142 ;; Built-in mathematical functions
143 `(,(regexp-opt '("abs" "acos" "all" "any" "asin" "atan" "atan2"
144 "ceil" "clamp" "cos" "cosh" "cross" "degrees"
145 "determinant" "distance" "dot" "exp" "exp2"
146 "faceforward" "floor" "fmod" "frac" "frexp"
147 "fwidth" "ldexp" "length" "lerp" "log" "log2"
148 "log10" "max" "min" "modf" "mul" "normalize"
149 "pow" "radians" "reflect" "refract" "round"
150 "rsqrt" "saturate" "sign" "sin" "sincos" "sinh"
151 "smoothstep" "sqrt" "step" "tan" "tanh" "transpose"
152 "trunc" "ddx" "ddy" "ddx_coarse" "ddy_coarse"
153 "ddx_fine" "ddy_fine" "tex1D" "tex2D" "tex3D"
154 "texCUBE" "noise" "clip" "discard" "lit")
155 'words)
156 . 'font-lock-builtin-face)
157
158 ;; Shader function intrinsics
159 `(,(regexp-opt '("Sample" "SampleLevel" "SampleBias" "SampleCmp"
160 "SampleCmpLevelZero" "SampleGrad" "Load" "Store"
161 "GetDimensions" "CalculateLevelOfDetail"
162 "CalculateLevelOfDetailUnclamped"
163 "Gather" "GatherRed" "GatherGreen" "GatherBlue"
164 "GatherAlpha" "GatherCmp" "GatherCmpRed"
165 "GatherCmpGreen" "GatherCmpBlue" "GatherCmpAlpha"
166 "GroupMemoryBarrier" "GroupMemoryBarrierWithGroupSync"
167 "DeviceMemoryBarrier" "DeviceMemoryBarrierWithGroupSync"
168 "AllMemoryBarrier" "AllMemoryBarrierWithGroupSync"
169 "InterlockedAdd" "InterlockedAnd" "InterlockedCompareExchange"
170 "InterlockedCompareStore" "InterlockedExchange"
171 "InterlockedMax" "InterlockedMin" "InterlockedOr"
172 "InterlockedXor" "WaveActiveAllEqual" "WaveActiveBallot"
173 "WaveActiveCountBits" "WaveGetLaneCount" "WaveGetLaneIndex"
174 "WaveIsFirstLane" "WaveActiveAnyTrue" "WaveActiveAllTrue"
175 "WaveActiveSum" "WaveActiveProduct" "WaveActiveMin"
176 "WaveActiveMax" "WaveActiveBitAnd" "WaveActiveBitOr"
177 "WaveActiveBitXor" "WavePrefixCountBits" "WavePrefixSum"
178 "WavePrefixProduct" "WaveQuadReadAcrossX" "WaveQuadReadAcrossY"
179 "WaveQuadReadAcrossDiagonal" "WaveQuadSwapX" "WaveQuadSwapY"
180 "WaveReadLaneAt" "WaveReadLaneFirst")
181 'words)
182 . 'font-lock-builtin-face)
183
184 ;; Number literals
185 '("\\b[0-9]+\\(\\.[0-9]+\\)?\\([eE][-+]?[0-9]+\\)?[fFhHlLuU]*\\b" . 'font-lock-constant-face)
186 '("\\b0[xX][0-9a-fA-F]+[uUlL]*\\b" . 'font-lock-constant-face)
187
188 ;; String literals
189 '("\"\\([^\"\\\\]\\|\\\\.\\)*\"" . 'font-lock-string-face)
190 '("'\\([^'\\\\]\\|\\\\.\\)*'" . 'font-lock-string-face)
191
192 ;; Function definitions
193 '("\\b\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\s-*(" (1 'font-lock-function-name-face))
194
195 ;; Type names (capitalized identifiers)
196 '("\\b[A-Z][a-zA-Z0-9_]*\\b" . 'font-lock-type-face)
197 )
198 "Font lock keywords for Slang mode.")
199
200;; Imenu support
201(defvar slang-imenu-generic-expression
202 '(("Functions" "^\\s-*\\([a-zA-Z_][a-zA-Z0-9_<>]*\\)\\s-+\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\s-*(" 2)
203 ("Structs" "^\\s-*struct\\s-+\\([a-zA-Z_][a-zA-Z0-9_]*\\)" 1)
204 ("Interfaces" "^\\s-*interface\\s-+\\([a-zA-Z_][a-zA-Z0-9_]*\\)" 1)
205 ("Enums" "^\\s-*enum\\s-+\\([a-zA-Z_][a-zA-Z0-9_]*\\)" 1)
206 ("Classes" "^\\s-*class\\s-+\\([a-zA-Z_][a-zA-Z0-9_]*\\)" 1))
207 "Imenu generic expression for Slang mode.")
208
209;; Indentation function
210(defun slang-indent-line ()
211 "Indent current line as Slang code."
212 (interactive)
213 (c-indent-line))
214
215;; Electric brace function
216(defun slang-electric-brace (arg)
217 "Insert a brace and indent properly."
218 (interactive "P")
219 (self-insert-command (prefix-numeric-value arg))
220 (when (and (not arg)
221 (eolp)
222 (save-excursion
223 (skip-chars-backward " \t")
224 (bolp)))
225 (c-indent-line)))
226
227;; Keymap
228(defvar slang-mode-map
229 (let ((map (make-sparse-keymap)))
230 (define-key map "{" 'slang-electric-brace)
231 (define-key map "}" 'slang-electric-brace)
232 (define-key map (kbd "C-c C-c") 'comment-region)
233 (define-key map (kbd "C-c C-u") 'uncomment-region)
234 map)
235 "Keymap for Slang mode.")
236
237;; Mode menu
238(easy-menu-define slang-mode-menu slang-mode-map
239 "Menu for Slang mode."
240 '("Slang"
241 ["Comment Region" comment-region (mark)]
242 ["Uncomment Region" uncomment-region (mark)]
243 "---"
244 ["Indent Line" slang-indent-line t]
245 ["Indent Region" indent-region (mark)]
246 "---"
247 ["Customize Slang" (customize-group 'slang) t]))
248
249;;;###autoload
250(define-derived-mode slang-mode c-mode "Slang"
251 "Major mode for editing Slang shader files."
252 :syntax-table slang-mode-syntax-table
253 :group 'slang
254
255 ;; Font lock
256 (setq font-lock-defaults '(slang-font-lock-keywords nil nil nil nil))
257
258 ;; Comments
259 (setq comment-start "// "
260 comment-end ""
261 comment-start-skip "\\(//+\\|/\\*+\\)\\s *"
262 comment-end-skip "\\s *\\(\\s>\\|\\*+/\\)")
263
264 ;; Indentation
265 (setq c-basic-offset slang-indent-offset
266 tab-width slang-indent-offset
267 indent-tabs-mode nil)
268
269 ;; Case sensitivity
270 (setq case-fold-search nil)
271
272 ;; Imenu
273 (setq imenu-generic-expression slang-imenu-generic-expression)
274
275 ;; Compilation support
276 (when (boundp 'compilation-error-regexp-alist)
277 (set (make-local-variable 'compilation-error-regexp-alist)
278 '(("^\\([^:]+\\):\\([0-9]+\\):" 1 2))))
279
280 ;; Run mode hooks
281 (run-mode-hooks 'slang-mode-hook))
282
283;; File associations
284;;;###autoload
285(add-to-list 'auto-mode-alist '("\\.slang\\'" . slang-mode))
286;;;###autoload
287(add-to-list 'auto-mode-alist '("\\.sl\\'" . slang-mode))
288;;;###autoload
289(add-to-list 'auto-mode-alist '("\\.slangh\\'" . slang-mode))
290
291(provide 'slang-mode)
292
293;;; slang-mode.el ends here