dot-emacs/local-lisp/hlsl-mode.el

582 lines
23 KiB
EmacsLisp

;;; hlsl-mode.el --- Major mode for HLSL shader files -*- lexical-binding: t; -*-
;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
;; Copyright (C) 2011, 2014, 2019 Jim Hourihan
;; Copyright (C) 2022 Jcaw
;;
;; Authors: Xavier.Decoret@imag.fr,
;; Jim Hourihan <jimhourihan ~at~ gmail.com>
;; GitHub user "jcaw"
;; Keywords: languages HLSL GPU shaders
;; Version: 1.1.3
;; URL: https://github.com/jcaw/hlsl-mode
;; Package-Requires: ((emacs "24.4"))
;;
;; Original URL http://artis.inrialpes.fr/~Xavier.Decoret/resources/glsl-mode/
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Major mode for editing OpenHLSL grammar files, usually files ending with
;; `.fx[hc]', `.hlsl', `.shader', `.compute'. It is based on c-mode plus some
;; features and pre-specified fontifications.
;;
;; It is modified from `glsl-mode', maintained at the time of writing by Jim
;; Hourihan: https://github.com/jimhourihan/glsl-mode
;; This package provides the following features:
;; * Syntax coloring (via font-lock) for grammar symbols and
;; builtin functions and variables for HLSL (up to the version specified
;; by `hlsl-shader-model-version')
;; * Indentation for the current line (TAB) and selected region (C-M-\).
;;; Code:
(require 'cc-mode)
(eval-when-compile ; required and optional libraries
(require 'find-file)
(require 'subr-x))
(require 'align)
(defgroup hlsl nil
"Microsoft HLSL Major Mode."
:group 'languages)
(defconst hlsl-shader-model-version "6.0"
"Shader model version number.")
(defconst hlsl-direct3d-version "12"
"Direct3D language version number.")
(defvar hlsl-type-face 'hlsl-type-face)
(defface hlsl-type-face
'((t (:inherit font-lock-type-face))) "HLSL: type face."
:group 'hlsl)
(defvar hlsl-builtin-face 'hlsl-builtin-face)
(defface hlsl-builtin-face
'((t (:inherit font-lock-builtin-face))) "HLSL: builtin face."
:group 'hlsl)
(defvar hlsl-deprecated-builtin-face 'hlsl-deprecated-builtin-face)
(defface hlsl-deprecated-builtin-face
'((t (:inherit font-lock-warning-face))) "HLSL: deprecated builtin face."
:group 'hlsl)
(defvar hlsl-qualifier-face 'hlsl-qualifier-face)
(defface hlsl-qualifier-face
'((t (:inherit font-lock-keyword-face))) "HLSL: qualifier face."
:group 'hlsl)
(defvar hlsl-keyword-face 'hlsl-keyword-face)
(defface hlsl-keyword-face
'((t (:inherit font-lock-keyword-face))) "HLSL: keyword face."
:group 'hlsl)
(defvar hlsl-deprecated-keyword-face 'hlsl-deprecated-keyword-face)
(defface hlsl-deprecated-keyword-face
'((t (:inherit font-lock-warning-face))) "HLSL: deprecated keyword face."
:group 'hlsl)
(defvar hlsl-variable-name-face 'hlsl-variable-name-face)
(defface hlsl-variable-name-face
'((t (:inherit font-lock-variable-name-face))) "HLSL: variable face."
:group 'hlsl)
(defvar hlsl-deprecated-variable-name-face 'hlsl-deprecated-variable-name-face)
(defface hlsl-deprecated-variable-name-face
'((t (:inherit font-lock-warning-face))) "HLSL: deprecated variable face."
:group 'hlsl)
(defvar hlsl-reserved-keyword-face 'hlsl-reserved-keyword-face)
(defface hlsl-reserved-keyword-face
'((t (:inherit hlsl-keyword-face))) "HLSL: reserved keyword face."
:group 'hlsl)
(defvar hlsl-preprocessor-face 'hlsl-preprocessor-face)
(defface hlsl-preprocessor-face
'((t (:inherit font-lock-preprocessor-face))) "HLSL: preprocessor face."
:group 'hlsl)
(defcustom hlsl-additional-types nil
"List of additional keywords to be considered types.
These are added to the `hlsl-type-list' and are fontified using
the `hlsl-type-face'. Examples of existing types include
\"float\", \"float4\", and \"RWStructuredBuffer\"."
:type '(repeat (string :tag "Type Name"))
:group 'hlsl)
(defcustom hlsl-additional-qualifiers nil
"List of additional keywords to be considered qualifiers.
These are added to the `hlsl-qualifier-list' and are fontified
using the `hlsl-qualifier-face'. Examples of existing qualifiers
include \"const\", \"in\", and \"out\"."
:type '(repeat (string :tag "Qualifier Name"))
:group 'hlsl)
(defcustom hlsl-additional-keywords nil
"List of additional HLSL keywords.
These are added to the `hlsl-keyword-list' and are fontified
using the `hlsl-keyword-face'. Example existing keywords include
\"while\", \"if\", and \"return\"."
:type '(repeat (string :tag "Keyword"))
:group 'hlsl)
(defcustom hlsl-additional-built-ins nil
"List of additional functions to be considered built-in.
These are added to the `hlsl-builtin-list' and are fontified
using the `hlsl-builtin-face'."
:type '(repeat (string :tag "Keyword"))
:group 'hlsl)
(defvar hlsl-mode-map
(let ((hlsl-mode-map (make-sparse-keymap)))
(define-key hlsl-mode-map [S-iso-lefttab] 'ff-find-other-file)
hlsl-mode-map)
"Keymap for HLSL major mode.")
;; (defcustom hlsl-browse-url-function 'browse-url
;; "Function used to display HLSL man pages.
;; E.g. `browse-url', `eww', `w3m', etc."
;; :type 'function
;; :group 'hlsl)
;; (defcustom hlsl-man-pages-base-url "http://www.opengl.org/sdk/docs/man/html/"
;; "Location of GL man pages."
;; :type 'string
;; :group 'hlsl)
;;;###autoload
(progn
(add-to-list 'auto-mode-alist '("\\.fx\\'" . hlsl-mode))
(add-to-list 'auto-mode-alist '("\\.fxc\\'" . hlsl-mode))
(add-to-list 'auto-mode-alist '("\\.fxh\\'" . hlsl-mode))
(add-to-list 'auto-mode-alist '("\\.hlsl\\'" . hlsl-mode))
(add-to-list 'auto-mode-alist '("\\.cg\\'" . hlsl-mode))
;; Unity shader format
(add-to-list 'auto-mode-alist '("\\.shader\\'" . hlsl-mode))
;; Unity shader include suffix
(add-to-list 'auto-mode-alist '("\\.cginc\\'" . hlsl-mode))
;; Unity compute shaders are HLSL
(add-to-list 'auto-mode-alist '("\\.compute\\'" . hlsl-mode))
)
(eval-and-compile
(defun hlsl--mixed-case (strings)
"Get original `strings', plus lowercase and uppercase versions.
For example:
(hlsl--mixed-case '(\"TexCoord\" \"POSITION\"))
-> '(\"TexCoord\" \"TEXCOORD\" \"Texcoord\"
\"POSITION\" \"Position\")
Returns a flattened list of all the resultant strings (without
duplicates)."
(apply #'append (mapcar (lambda (s)
(if (= 0 (length s))
s
(delete-dups
(list s (upcase s)
(concat (upcase (substring s 0 1))
(downcase (substring s 1)))))))
strings)))
;; These vars are useful for completion so keep them around after compile as
;; well. The goal here is to have the byte compiled code have optimized
;; regexps so its not done at eval time.
(defvar hlsl-type-list
`(
;; TODO: Maybe make `void' a keyword?
"matrix" "void"
;; Numeric scalars, plus all the vector and matrix expressions for each. E.g:
;; float, float1, float1x2, uint2, bool3x4, etc.
,@(mapcar (lambda (type)
(concat type "\\([1234]?\\|\\([1234]x[1234]\\)?\\)"))
'("bool" "int" "uint" "float"
"min16float" "min10float" "min16int" "min12int" "min16uint"))
;; These numeric scalars don't expand to vectors/matrices
"half" "dword" "double"
;; Texture samplers
"sampler" "sampler1D" "sampler2D" "sampler3D" "samplerCUBE" "sampler_state"
"SamplerState" "SampleComparisonState"
;; Buffer-esque types
"AppendStructuredBuffer" "Buffer" "ByteAddressBuffer" "ConsumeStructuredBuffer"
"InputPatch" "OutputPatch" "RWBuffer" "RWByteAddressBuffer" "RWStructuredBuffer"
"RWTexture1D" "RWTexture1DArray" "RWTexture2D" "RWTexture2DArray" "RWTexture3D"
"StructuredBuffer" "Texture1D" "Texture1DArray" "Texture2D" "Texture2DArray"
"Texture2DMS" "Texture2DMSArray" "Texture3D" "TextureCube" "TextureCubeArray"
;; Rasterizer Order Views
"RasterizerOrderedBuffer" "RasterizerOrderedByteAddressBuffer" "RasterizerOrderedStructuredBuffer"
"RasterizerOrderedTexture1D" "RasterizerOrderedTexture1DArray" "RasterizerOrderedTexture2D"
"RasterizerOrderedTexture2DArray" "RasterizerOrderedTexture3D"
;; Misc
;;
;; TODO: Double check Object2 usage
"Object2"
;; Geometry shader stream outputs
"PointStream" "LineStream" "TriangleStream"))
(defvar hlsl-qualifier-list
'(
;; Misc
"snorm" "unorm" "in" "inline" "inout" "precise" "extern" "nointerpolation"
"precise" "shared" "groupshared" "static" "uniform" "volatile" "const"
"row_major" "column_major" "export" "linear" "centroid" "noperspective"
"sample" "globallycoherent" "out"
;; Geom shader primitives
"point" "line" "triangle" "lineadj" "triangledj"
"pixelfragment" "vertexfragment"))
(defvar hlsl-keyword-list
`(
;; Special types
"true" "false" "NULL" "null"
;; Misc
"compile_fragment" "class" "interface" "break" "continue" "do" "default"
"discard" "for" "while" "if" "else" "return" "struct" "switch" "case"
"register" "packoffset" "cbuffer" "tbuffer" "fxgroup" "pass"
"technique[1-9]?[1-9]?"
"SetVertexShader" "SetGeometryShader" "SetPixelSader"
;; Attributes
"maxvertexcount" "domain" "earlydepthstencil" "instance" "maxtessfactor"
"numthreads" "outputcontrolpoints" "outputtopology" "partitioning"
"patchconstantfunc"
;; domain types
;; TODO: move these into a dedicated domain matcher?
;; TODO: `point' and `line' at least are duplicated here and in qualifiers
;; TODO: Take another look at these, they should probably be handled differently
"tri" "quad" "isoline" "point" "line" "triangle_cw" "triangle_ccw"
"integer" "fractional_even" "fractional_odd" "pow2"
;; Branching attributes
"unroll" "loop" "fastopt" "allow_uav_condition" "branch" "flatten"
"forcecase" "call"
;; Shader profiles
;;
;; Shader Model 1
"vs_1_1"
;; Shader Model 2
"ps_2_0" "ps_2_x" "vs_2_0" "vs_2_x" "ps_4_0_level_9_0" "ps_4_0_level_9_1"
"ps_4_0_level_9_3" "vs_4_0_level_9_0" "vs_4_0_level_9_1" "vs_4_0_level_9_3"
"lib_4_0_level_9_1" "lib_4_0_level_9_"
;; Shader Model 3
"ps_3_0" "vs_3_0"
;; Shader Model 4
"cs_4_0" "gs_4_0" "ps_4_0" "vs_4_0" "cs_4_1" "gs_4_1" "ps_4_1" "vs_4_1"
"lib_4_0" "lib_4_"
;; Shader Model 5
"cs_5_0" "ds_5_0" "gs_5_0" "hs_5_0" "ps_5_0" "vs_5_0" "lib_5_"
;; Shader Model 6
"cs_6_0" "ds_6_0" "gs_6_0" "hs_6_0" "ps_6_0" "vs_6_0" "lib_6_"
;; FX Profiles
"fx_1_0" "fx_2_0" "fx_4_0" "fx_4_1" "fx_5_0"
;; Semantics
;;
;; All semantics are case-insensitive, so allow uppercase, lowercase and
;; capitalised versions. Other/weird mixtures of case will not be
;; highlighted for now, even though the HLSL spec allows them.
,@(hlsl--mixed-case
'("Binormal[0-9]?" "BlendIndices[0-9]?" "BlendWeight[0-9]?" "Color[0-9]?"
"Normal[0-9]?" "Position[0-9]?" "PositionT" "PSize[0-9]?" "Tangent[0-9]?"
"TexCoord[0-9]" "Fog" "TessFactor[0-9]?" "VFace" "VPos" "Depth[0-9]?"
"SV_ClipDistance[0-9]?" "SV_CullDistance[0-9]?" "SV_Coverage" "SV_Depth"
"SV_DepthGreaterEqual" "SV_DepthLessEqual" "SV_DispatchThreadID"
"SV_DomainLocation" "SV_GroupID" "SV_GroupIndex" "SV_GroupThreadID"
"SV_GSInstanceID" "SV_InnerCoverage" "SV_InsideTessFactor" "SV_InstanceID"
"SV_IsFrontFace" "SV_OutputControlPointID" "SV_Position" "SV_PrimitiveID"
"SV_RenderTargetArrayIndex" "SV_SampleIndex" "SV_StencilRef" "SV_Target[0-7]"
"SV_TessFactor" "SV_VertexID" "SV_ViewportArrayIndex" "SV_ShadingRate"
"SV_Target"
;; Misc Semantics
"BezierPos" "WorldPos" "TanUCorner" "TanVCorner" "TanWeights" "Bitangent[0-9]?"))
;; Unity keywords
;;
;; TODO: Separate derived mode for Unity ".shader" files? They're not strictly HLSL.
"Shader" "Properties" "SubShader" "Tags" "Pass" "CGPROGRAM" "ENDCG"))
(defvar hlsl-reserved-list
'(
;; [2022/01/31] Just the reserved words found on:
;; https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-reserved-words
"auto" "case" "catch" "char" "class" "const_cast" "default" "delete" "dynamic_cast"
"enum" "explicit" "friend" "goto" "long" "mutable" "new" "operator" "private"
"protected" "public" "reinterpret_cast" "short" "signed" "sizeof" "static_cast"
"template" "this" "throw" "try" "typename" "union" "unsigned" "using" "virtual"))
(defvar hlsl-deprecated-qualifier-list
'())
(defvar hlsl-builtin-list
'(
;; This is the list of the builtins taken directly from the Direct3D 12 docs (Shader Model 6.0)
"abort" "abs" "acos" "all" "AllMemoryBarrier" "AllMemoryBarrierWithGroupSync"
"any" "asdouble" "asfloat" "asin" "asint" "asint" "asuint" "asuint" "atan" "atan2"
"ceil" "CheckAccessFullyMapped" "clamp" "clip" "cos" "cosh" "countbits" "cross"
"D3DCOLORtoUBYTE4" "ddx" "ddx_coarse" "ddx_fine" "ddy" "ddy_coarse" "ddy_fine"
"degrees" "determinant" "DeviceMemoryBarrier" "DeviceMemoryBarrierWithGroupSync"
"distance" "dot" "dst" "errorf" "EvaluateAttributeAtCentroid" "EvaluateAttributeAtSample"
"EvaluateAttributeSnapped" "exp" "exp2" "f16tof32" "f32tof16" "faceforward"
"firstbithigh" "firstbitlow" "floor" "fma" "fmod" "frac" "frexp" "fwidth"
"GetRenderTargetSampleCount" "GetRenderTargetSamplePosition" "GroupMemoryBarrier"
"GroupMemoryBarrierWithGroupSync" "InterlockedAdd" "InterlockedAnd"
"InterlockedCompareExchange" "InterlockedCompareStore" "InterlockedExchange"
"InterlockedMax" "InterlockedMin" "InterlockedOr" "InterlockedXor" "isfinite"
"isinf" "isnan" "ldexp" "length" "lerp" "lit" "log" "log10" "log2" "mad" "max"
"min" "modf" "msad4" "mul" "noise" "normalize" "pow" "printf"
"Process2DQuadTessFactorsAvg" "Process2DQuadTessFactorsMax" "Process2DQuadTessFactorsMin"
"ProcessIsolineTessFactors" "ProcessQuadTessFactorsAvg" "ProcessQuadTessFactorsMax"
"ProcessQuadTessFactorsMin" "ProcessTriTessFactorsAvg" "ProcessTriTessFactorsMax"
"ProcessTriTessFactorsMin" "radians" "rcp" "reflect" "refract" "reversebits"
"round" "rsqrt" "saturate" "sign" "sin" "sincos" "sinh" "smoothstep" "sqrt"
"step" "tan" "tanh" "tex1D" "tex1Dbias" "tex1Dgrad" "tex1Dlod" "tex1Dproj"
"tex2D" "tex2Dbias" "tex2Dgrad" "tex2Dlod" "tex2Dproj" "tex3D" "tex3Dbias"
"tex3Dgrad" "tex3Dlod" "tex3Dproj" "texCUBE" "texCUBEbias" "texCUBEgrad" "texCUBElod"
"texCUBEproj" "transpose" "trunc"
;; Geometry shader streams
"Append" "RestartStrip"
;; Textures/Buffers
"CalculateLevelOfDetail" "CalculateLevelOfDetailUnclamped" "Gather" "GetDimensions"
"GetSamplePosition" "Sample" "SampleBias" "SampleCmp" "SampleGrad" "SampleLevel"
"Operator\\[\\]" "Load[234]?" "Store[234]?"
"GatherRed" "GatherGreen" "GatherBlue" "GatherAlpha" "GatherCmp" "GatherCmpRed"
"GatherCmpGreen" "GatherCmpBlue" "GatherCmpAlpha"
"Sample" "SampleBias" "SampleCmp" "SampleCmpLevelZero" "SampleGrad" "SampleLevel"
;; Wave Intrinsics
"QuadReadAcrossDiagonal" "QuadReadLaneAt" "QuadReadAcrossX" "QuadReadAcrossY"
"WaveActiveAllEqual" "WaveActiveBitAnd" "WaveActiveBitOr" "WaveActiveBitXor"
"WaveActiveCountBits" "WaveActiveMax" "WaveActiveMin" "WaveActiveProduct"
"WaveActiveSum" "WaveActiveAllTrue" "WaveActiveAnyTrue" "WaveActiveBallot"
"WaveGetLaneCount" "WaveGetLaneIndex" "WaveIsFirstLane" "WavePrefixCountBits"
"WavePrefixProduct" "WavePrefixSum" "WaveReadLaneFirst" "WaveReadLaneAt"
;; Unsorted
"Consume" "DecrementCounter" "IncrementCounter"))
(defvar hlsl-deprecated-builtin-list
'())
(defvar hlsl-deprecated-variables-list
'())
(defvar hlsl-preprocessor-directive-list
'(
"define" "elif" "else" "endif" "error" "if" "ifdef" "ifndef" "include"
"line" "pragma" "undef"))
(defvar hlsl-preprocessor-expr-list
'(
;; Taken directly from glsl-mode - not audited yet
"defined" "##"))
(defvar hlsl-preprocessor-builtin-list
'(
;; Taken directly from glsl-mode - not audited yet
"__LINE__" "__FILE__" "__VERSION__"))
;; TODO: Highlighting for annotations <int something=27;>
) ; eval-and-compile
(eval-and-compile
(defun hlsl-ppre (re)
;; FIXME: This doesn't sanitise the inputs, so a bad member could corrupt the whole expression
(format "\\<\\(%s\\)\\>" (string-join re "\\|"))))
(defvar hlsl-font-lock-keywords-1
(append
(list
(cons (eval-when-compile
(format "^[ \t]*#[ \t]*\\<\\(%s\\)\\>"
(regexp-opt hlsl-preprocessor-directive-list)))
hlsl-preprocessor-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-type-list))
hlsl-type-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-deprecated-qualifier-list))
hlsl-deprecated-keyword-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-reserved-list))
hlsl-reserved-keyword-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-qualifier-list))
hlsl-qualifier-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-keyword-list))
hlsl-keyword-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-preprocessor-builtin-list))
hlsl-keyword-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-deprecated-builtin-list))
hlsl-deprecated-builtin-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-builtin-list))
hlsl-builtin-face)
(cons (eval-when-compile
(hlsl-ppre hlsl-deprecated-variables-list))
hlsl-deprecated-variable-name-face)
;; Swizzles are a special case. We want to highlight swizzles only when
;; they're after a dot, but we don't want to highlight the dot itself.
(list (eval-when-compile
;; TODO: Maybe these types of swizzles?
;; /\.\(_m[0-3]\{2}\)\{1,4\}/
;; /\.\(_[1-4]\{2}\)\{1,4\}/
"\\.\\_<\\([xyzw]\\{1,4\\}\\|[rgba]\\{1,4\\}\\)\\_>")
'(1 hlsl-builtin-face))
;; TODO: What to do about dedicated named variables?
;; (cons "unity_[A-Z0-9a-z_]+" hlsl-variable-name-face)
)
(when hlsl-additional-types
(list
(cons (hlsl-ppre hlsl-additional-types) hlsl-type-face)))
(when hlsl-additional-keywords
(list
(cons (hlsl-ppre hlsl-additional-keywords) hlsl-keyword-face)))
(when hlsl-additional-qualifiers
(list
(cons (hlsl-ppre hlsl-additional-qualifiers) hlsl-qualifier-face)))
(when hlsl-additional-built-ins
(list
(cons (hlsl-ppre hlsl-additional-built-ins) hlsl-builtin-face)))
)
"Highlighting expressions for HLSL mode.")
(defvar hlsl-font-lock-keywords hlsl-font-lock-keywords-1
"Default highlighting expressions for HLSL mode.")
(defvar hlsl-mode-syntax-table
(let ((hlsl-mode-syntax-table (make-syntax-table)))
(modify-syntax-entry ?/ ". 124b" hlsl-mode-syntax-table)
(modify-syntax-entry ?* ". 23" hlsl-mode-syntax-table)
(modify-syntax-entry ?\n "> b" hlsl-mode-syntax-table)
(modify-syntax-entry ?_ "w" hlsl-mode-syntax-table)
hlsl-mode-syntax-table)
"Syntax table for `hlsl-mode'.")
(defvar hlsl-other-file-alist
;; TODO: Add common pairings, e.g. vert & corresponding frag files, perhaps
;; also geom
'()
"Alist of extensions to find given the current file's extension.")
(defun hlsl-man-completion-list ()
"Return list of all HLSL keywords."
(append hlsl-builtin-list hlsl-deprecated-builtin-list))
;; TODO: Switch over to HLSL docs?
;; (defun hlsl-find-man-page (thing)
;; "Collects and displays manual entry for HLSL built-in function THING."
;; (interactive
;; (let ((word (current-word nil t)))
;; (list
;; (completing-read
;; (concat "OpenGL.org HLSL man page: (" word "): ")
;; (hlsl-man-completion-list)
;; nil nil nil nil word))))
;; (save-excursion
;; (apply hlsl-browse-url-function
;; (list (concat hlsl-man-pages-base-url thing ".xhtml")))))
;; TODO: Maybe remove easy menu?
(easy-menu-define hlsl-menu hlsl-mode-map
"HLSL Menu."
`("HLSL"
["Comment Out Region" comment-region
(c-fn-region-is-active-p)]
["Uncomment Region" (comment-region (region-beginning)
(region-end) '(4))
(c-fn-region-is-active-p)]
["Indent Expression" c-indent-exp
(memq (char-after) '(?\( ?\[ ?\{))]
["Indent Line or Region" c-indent-line-or-region t]
["Fill Comment Paragraph" c-fill-paragraph t]
"----"
["Backward Statement" c-beginning-of-statement t]
["Forward Statement" c-end-of-statement t]
"----"
["Up Conditional" c-up-conditional t]
["Backward Conditional" c-backward-conditional t]
["Forward Conditional" c-forward-conditional t]
"----"
["Backslashify" c-backslash-region (c-fn-region-is-active-p)]
"----"
["Find HLSL Man Page" hlsl-find-man-page t]
))
;;;###autoload
(define-derived-mode hlsl-mode prog-mode "HLSL"
"Major mode for editing HLSL shader files."
(c-initialize-cc-mode t)
(setq abbrev-mode t)
(c-init-language-vars-for 'c-mode)
(c-common-init 'c-mode)
(cc-imenu-init cc-imenu-c++-generic-expression)
(set (make-local-variable 'font-lock-defaults) '(hlsl-font-lock-keywords))
(set (make-local-variable 'ff-other-file-alist) 'hlsl-other-file-alist)
(set (make-local-variable 'comment-start) "// ")
(set (make-local-variable 'comment-end) "")
(set (make-local-variable 'comment-padding) "")
;; TODO: Indentation rules for annotated for loops, e.g:
;; [unroll] for (...) {
;; --->|
;; }
;; Currently it just indents flat as though no scope was declared
(add-to-list 'align-c++-modes 'hlsl-mode)
(c-run-mode-hooks 'c-mode-common-hook)
(run-mode-hooks 'hlsl-mode-hook)
;; TODO: Guard `c-make-noise-macro-regexps' based on Emacs version, then lower
;; dependency.
:after-hook (progn (when (fboundp 'c-make-noise-macro-regexps)
;; Depends on Emacs 26.1, guarding this allows us to
;; support down to Emacs 24.4
(c-make-noise-macro-regexps))
(c-make-macro-with-semi-re)
(c-update-modeline)))
;; TODO: Float number highlighting (i.e. 1.0f)
;; TODO: Negative number highlighting
;; TODO: Highlight numbers adjacent to operators e.g. 1-variable
(provide 'hlsl-mode)
;;; hlsl-mode.el ends here