<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "language.dtd"
[
  <!ENTITY var_name_re "[A-Za-z_][_0-9A-Za-z]*">
  <!ENTITY unary_operators  "\B-[abcdefghkprstuwxGLNOSovRnz]\b">
  <!ENTITY binary_operators "\B(?:-(?:e[fq]|[nolg]t|[nlg]e)|==?|!=)\b">
]>
<!--
    This file is part of KDE's kate project.

    SPDX-FileCopyrightText: 2022-2023 Alex Turbov <i.zaufi@gmail.com>

    SPDX-License-Identifier: MIT
 -->
<language
    name="Earthfile"
    section="Other"
    version="1"
    kateversion="5.79"
    extensions="Earthfile"
    author="Alex Turbov (i.zaufi@gmail.com)"
    license="MIT"
  >
  <highlighting>

    <!-- https://docs.earthly.dev/docs/earthfile/builtin-args -->
    <list name="variables">
      <item>EARTHLY_TARGET_TAG</item>
      <item>EARTHLY_TARGET_PROJECT</item>
      <item>EARTHLY_TARGET_PROJECT_NO_TAG</item>
      <item>EARTHLY_TARGET_NAME</item>
      <item>EARTHLY_TARGET_TAG</item>
      <item>EARTHLY_TARGET_TAG_DOCKER</item>
      <item>EARTHLY_GIT_HASH</item>
      <item>EARTHLY_GIT_SHORT_HASH</item>
      <item>EARTHLY_GIT_ORIGIN_URL</item>
      <item>EARTHLY_GIT_PROJECT_NAME</item>
      <item>EARTHLY_GIT_COMMIT_TIMESTAMP</item>
      <item>EARTHLY_GIT_COMMIT_AUTHOR_TIMESTAMP</item>
      <item>EARTHLY_VERSION</item>
      <item>EARTHLY_BUILD_SHA</item>
      <item>TARGETPLATFORM</item>
      <item>TARGETOS</item>
      <item>TARGETARCH</item>
      <item>TARGETVARIANT</item>
      <item>EARTHLY_SOURCE_DATE_EPOCH</item>
      <item>USERPLATFORM</item>
      <item>USEROS</item>
      <item>USERARCH</item>
      <item>USERVARIANT</item>
    </list>

    <!--
      See `RUN` and `mount` option description
      https://docs.earthly.dev/docs/earthfile#run
    -->
    <list name="mount_keys">
      <item>type</item>
      <item>target</item>
      <item>mode</item>
      <item>id</item>
      <item>sharing</item>
    </list>

    <contexts>
      <context name="Base" attribute="Normal Text" lineEndContext="#stay">
        <RegExpr
            String="^[A-Z_][A-Z_0-9]+:"
            column="0"
            context="#stay"
            attribute="User Defined Command"
            endRegion="Recipe"
            beginRegion="Recipe"
          />
        <RegExpr
            String="^[a-z][a-z\-_0-9]+:"
            column="0"
            context="#stay"
            attribute="Target Name"
            endRegion="Recipe"
            beginRegion="Recipe"
          />
        <DetectSpaces />
        <IncludeRules context="RecipeCommands" />
      </context>

      <context name="RecipeCommands" attribute="Normal Text" lineEndContext="#pop">
        <DetectSpaces />
        <DetectChar char="#" attribute="Comment" context="Comment" />
        <!-- The whole file is a collection of recipes -->
        <WordDetect String="ARG" attribute="Command" context="ARG_ctx" />
        <WordDetect String="FROM" attribute="Command" context="FROM_ctx" />
        <WordDetect String="BUILD" attribute="Command" context="BUILD_ctx" />
        <WordDetect String="VERSION" attribute="Command" context="VERSION_ctx" />
        <WordDetect String="GIT" attribute="Command" context="GIT_ctx" />
        <WordDetect String="CACHE" attribute="Command" context="CACHE_ctx" />
        <WordDetect String="LOCALLY" attribute="Command" context="#stay" />
        <WordDetect String="COMMAND" attribute="Command" context="#stay" />
        <WordDetect String="IMPORT" attribute="Command" context="IMPORT_ctx" />
        <WordDetect String="CMD" attribute="Command" context="CMD_ctx" />
        <WordDetect String="LABEL" attribute="Command" context="LABEL_ctx" />
        <WordDetect String="EXPOSE" attribute="Command" context="EXPOSE_ctx" />
        <WordDetect String="ENV" attribute="Command" context="BashOneLine##Bash" />
        <WordDetect String="ENTRYPOINT" attribute="Command" context="ENTRYPOINT_ctx" />
        <WordDetect String="VOLUME" attribute="Command" context="VOLUME_ctx" />
        <WordDetect String="USER" attribute="Command" context="USER_ctx" />
        <WordDetect String="WORKDIR" attribute="Command" context="WORKDIR_ctx" />
        <WordDetect String="HEALTHCHECK" attribute="Command" context="HEALTHCHECK_ctx" />
        <WordDetect String="HOST" attribute="Command" context="HOST_ctx" />
        <WordDetect String="DO" attribute="Command" context="DO_ctx" />
        <WordDetect String="COPY" attribute="Command" context="COPY_ctx" />
        <WordDetect String="SAVE" attribute="Command" context="SAVE_ctx" />
        <WordDetect String="WAIT" attribute="Command" context="WAIT_ctx" beginRegion="WAIT" />
        <WordDetect String="WITH" attribute="Command" context="WITH_ctx" beginRegion="WITH" />
        <WordDetect String="FOR" attribute="Command" context="FOR_ctx" beginRegion="FOR" />
        <WordDetect String="RUN" attribute="Command" context="RUN_ctx" />
        <WordDetect String="IF" attribute="Command" context="IF_ctx" beginRegion="IF" />
      </context>

      <context name="RecipeContent" attribute="Normal Text" lineEndContext="#pop">
        <LineContinue />

        <DetectChar char="'" attribute="String SingleQ" context="StringSQ" />
        <DetectChar char="&quot;" attribute="String DoubleQ" context="StringDQ" />

        <!-- See https://docs.earthly.dev/docs/guides/target-ref#target-reference -->
        <RegExpr
          context="DetectReference"
          lookAhead="true"
          String="([a-z0-9_\-\./]+(:[A-Za-z0-9_\-\./]+)?)?(\+[A-Za-z0-9_\-]+)(/[^ ,]*)?"
          />
        <RegExpr String="--&var_name_re;=" lookAhead="true" context="BuildArg" />
        <DetectChar char="$" lookAhead="1" context="DispatchVariables" />
        <Int attribute="Integer" />
      </context>

      <context name="BuildArg" attribute="Normal Text" lineEndContext="#pop">
        <DetectChar char="=" attribute="Operator" context="#pop" />
        <RegExpr String="--&var_name_re;" attribute="Build Arg" />
      </context>

      <context name="DispatchVariables" attribute="Normal Text" lineEndContext="#pop">
        <IncludeRules context="DispatchVariablesBase" />
        <DetectChar char="$" context="#pop" />
      </context>

      <context name="DispatchVariablesBase" attribute="Normal Text" lineEndContext="#pop">
        <Detect2Chars char="$" char1="$" attribute="Variable" context="#pop" />
        <Detect2Chars char="$" char1="?" attribute="Variable" context="#pop" />
        <Detect2Chars char="$" char1="*" attribute="Variable" context="#pop" />
        <Detect2Chars char="$" char1="@" attribute="Variable" context="#pop" />
        <Detect2Chars char="$" char1="{" attribute="Variable" context="VarSubst" />
        <Detect2Chars char="$" char1="(" attribute="Variable" context="CommandSubst" />
        <RegExpr String="\$&var_name_re;" lookAhead="true" context="VarName" />
      </context>

      <context name="VarName" attribute="Normal Text" lineEndContext="#pop">
        <DetectChar char="$" attribute="Variable" context="#stay" />
        <RegExpr String="_&var_name_re;" attribute="Internal/Local Variable" context="#pop" />
        <keyword String="variables" insensitive="false" attribute="Builtin Variable" context="#pop" />
        <DetectIdentifier attribute="Variable" context="#pop" />
      </context>

      <context name="VarSubst" attribute="Normal Text" lineEndContext="#pop" fallthroughContext="#pop">
        <DetectChar char="}" attribute="Variable" context="#pop#pop" />
        <RegExpr String="_&var_name_re;" attribute="Internal/Local Variable" context="#stay" />
        <keyword String="variables" insensitive="false" attribute="Builtin Variable" context="#stay" />
        <DetectIdentifier attribute="Variable" />
        <Detect2Chars char=":" char1="+" attribute="Variable" context="#stay" />
        <Detect2Chars char=":" char1="-" attribute="Variable" context="#stay" />
      </context>

      <context name="DetectReference" attribute="Normal Text" lineEndContext="#pop" fallthroughContext="#pop">
        <StringDetect String="%1" dynamic="true" attribute="Reference" context="#stay" />
        <StringDetect String="%3" lookAhead="true" dynamic="true" context="TargetOrCommand" />
        <StringDetect String="%4" dynamic="true" attribute="Artifact Name" context="#stay" />
      </context>

      <context name="TargetOrCommand" attribute="Normal Text" lineEndContext="#pop" fallthroughContext="#pop">
        <RegExpr String="\+[A-Z_][A-Z_0-9]+" context="#pop" attribute="User Defined Command" />
        <RegExpr String="\+[a-z][a-z\-_0-9]+" context="#pop" attribute="Target Name" />
      </context>

      <!-- StringSQ consumes anything till ' -->
      <context name="StringSQ" attribute="String SingleQ" lineEndContext="#stay">
        <DetectSpaces />
        <DetectIdentifier />
        <LineContinue context="#stay" />
        <DetectChar char="'" attribute="String SingleQ" context="#pop" />
      </context>

      <!-- StringDQ consumes anything till ", substitutes vars and expressions -->
      <context name="StringDQ" attribute="String DoubleQ" lineEndContext="#stay">
        <DetectSpaces />
        <DetectIdentifier />
        <DetectChar char="&quot;" attribute="String DoubleQ" context="#pop" />
        <LineContinue context="#stay" />
        <DetectChar char="\" lookAhead="1" context="StringDQEscape" />
        <DetectChar char="$" lookAhead="1" context="StringDQDispatchVariables" />
      </context>

      <context name="StringDQEscape" attribute="String DoubleQ" lineEndContext="#pop">
        <Detect2Chars char="\" char1="&quot;" attribute="String Escape" context="#pop" />
        <Detect2Chars char="\" char1="$" attribute="String Escape" context="#pop" />
        <Detect2Chars char="\" char1="n" attribute="String Escape" context="#pop" />
        <Detect2Chars char="\" char1="r" attribute="String Escape" context="#pop" />
        <Detect2Chars char="\" char1="t" attribute="String Escape" context="#pop" />
        <Detect2Chars char="\" char1="\" attribute="String Escape" context="#pop" />
        <!-- TODO REALLY? -->
        <LineContinue attribute="String Escape" context="#pop" />
        <DetectChar char="\" attribute="String DoubleQ" context="#pop" />
      </context>

      <context name="StringDQDispatchVariables" attribute="Normal Text" lineEndContext="#pop" fallthroughContext="#pop">
        <IncludeRules context="DispatchVariablesBase" />
        <DetectChar char="$" attribute="String DoubleQ" context="#pop" />
      </context>

      <!-- SubstCommand is called after a $( is encountered -->
      <context name="CommandSubst" attribute="Normal Text" lineEndContext="#stay" fallthroughContext="#pop">
        <LineContinue context="#stay" />
        <DetectChar char=")" attribute="Variable" context="#pop" />
        <!-- TODO Need a FIX for this:

            ARG _python_ver = $(${python_bin} -c \"import sys; print(\'{}.{}\'.format(*sys.version_info))\")
        -->
        <IncludeRules context="BashOneLine##Bash" />
      </context>

      <context name="Comment" attribute="Comment" lineEndContext="#pop">
        <LineContinue context="#stay" />
        <IncludeRules context="##Comments" />
      </context>

      <!--
          Earthly Commands
      -->

      <!-- https://docs.earthly.dev/docs/earthfile#arg -->
      <context name="ARG_ctx" attribute="Normal Text" lineEndContext="#pop">
        <StringDetect String="--required" attribute="Command Option" context="#stay" />
        <RegExpr String="_&var_name_re;" attribute="Internal/Local Variable" context="#stay" />
        <keyword String="variables" insensitive="false" attribute="Builtin Variable" context="#stay" />
        <DetectIdentifier attribute="Variable" context="#stay" />
        <DetectChar char="=" attribute="Operator" context="#pop!RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#build -->
      <context name="BUILD_ctx" attribute="Normal Text" lineEndContext="#pop">
        <StringDetect String="--platform" attribute="Command Option" context="#stay" />
        <StringDetect String="--allow-privileged" attribute="Command Option" context="#stay" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#do -->
      <context name="DO_ctx" attribute="Normal Text" lineEndContext="#pop">
        <StringDetect String="--allow-privileged" attribute="Command Option" context="#stay" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#copy -->
      <context name="COPY_ctx" attribute="Normal Text" lineEndContext="#pop">
        <StringDetect String="--dir" attribute="Command Option" context="#stay" />
        <StringDetect String="--keep-ts" attribute="Command Option" context="#stay" />
        <StringDetect String="--keep-own" attribute="Command Option" context="#stay" />
        <StringDetect String="--if-exists" attribute="Command Option" context="#stay" />
        <StringDetect String="--platform" attribute="Command Option" context="#stay" />
        <StringDetect String="--allow-privileged" attribute="Command Option" context="#stay" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#cache-beta -->
      <context name="CACHE_ctx" attribute="Normal Text" lineEndContext="#pop">
        <StringDetect String="--sharing" attribute="Command Option" context="#stay" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#expose-same-as-dockerfile-expose -->
      <context name="EXPOSE_ctx" attribute="Normal Text" lineEndContext="#pop">
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#user-same-as-dockerfile-user -->
      <context name="USER_ctx" attribute="Normal Text" lineEndContext="#pop">
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#workdir-same-as-dockerfile-workdir -->
      <context name="WORKDIR_ctx" attribute="Normal Text" lineEndContext="#pop">
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#healthcheck-same-as-dockerfile-workdir -->
      <context name="HEALTHCHECK_ctx" attribute="Normal Text" lineEndContext="#pop">
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#host-same-as-dockerfile-workdir -->
      <context name="HOST_ctx" attribute="Normal Text" lineEndContext="#pop">
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#cmd-same-as-dockerfile-cmd -->
      <context name="CMD_ctx" attribute="Normal Text" lineEndContext="#pop">
        <AnyChar String="[," attribute="Operator" context="#stay" />
        <DetectChar attribute="Operator" context="#pop" char="]" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#entrypoint-same-as-dockerfile-entrypoint -->
      <!-- TODO Deduplicate? -->
      <context name="ENTRYPOINT_ctx" attribute="Normal Text" lineEndContext="#pop">
        <AnyChar String="[," attribute="Operator" context="#stay" />
        <DetectChar char="]" attribute="Operator" context="#pop" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#volume-same-as-dockerfile-volume -->
      <!-- TODO Deduplicate? -->
      <context name="VOLUME_ctx" attribute="Normal Text" lineEndContext="#pop">
        <AnyChar String="[," attribute="Operator" context="#stay" />
        <DetectChar char="]" attribute="Operator" context="#pop" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#label-same-as-dockerfile-label -->
      <context name="LABEL_ctx" attribute="Normal Text" lineEndContext="#pop">
        <DetectChar char="=" attribute="Operator" context="#stay" />
        <IncludeRules context="RecipeContent" />
        <LineContinue context="#stay" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#import -->
      <context name="IMPORT_ctx" attribute="Normal Text" lineEndContext="#pop">
        <StringDetect String="--allow-privileged" attribute="Command Option" context="#stay" />
        <WordDetect String="AS" attribute="Command" context="#stay" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#version -->
      <context name="VERSION_ctx" attribute="Normal Text" lineEndContext="#pop">
        <!-- https://docs.earthly.dev/docs/earthfile/features#feature-flags -->
        <StringDetect String="--use-copy-include-patterns" attribute="Command Option" context="#stay" />
        <StringDetect String="--referenced-save-only" attribute="Command Option" context="#stay" />
        <StringDetect String="--for-in" attribute="Command Option" context="#stay" />
        <StringDetect String="--require-force-for-unsafe-saves" attribute="Command Option" context="#stay" />
        <StringDetect String="--no-implicit-ignore" attribute="Command Option" context="#stay" />
        <StringDetect String="--earthly-version-arg" attribute="Command Option" context="#stay" />
        <StringDetect String="--shell-out-anywhere" attribute="Command Option" context="#stay" />
        <StringDetect String="--use-registry-for-with-docker" attribute="Command Option" context="#stay" />
        <!--Other not from the list -->
        <StringDetect String="--wait-block" attribute="Command Option" context="#stay" />
        <StringDetect String="--use-cache-command" attribute="Command Option" context="#stay" />
        <RegExpr String="[0-9](\.[0-9])*" context="#pop" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#git-clone -->
      <context name="GIT_ctx" attribute="Normal Text" lineEndContext="#pop">
        <WordDetect String="CLONE" attribute="Command" context="#stay" />
        <StringDetect String="--branch" attribute="Command Option" context="#stay" />
        <StringDetect String="--keep-ts" attribute="Command Option" context="#stay" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#wait-experimental -->
      <context name="WAIT_ctx" attribute="Normal Text" lineEndContext="#stay">
        <WordDetect String="END" attribute="Command" context="#pop" endRegion="WAIT" />
        <IncludeRules context="RecipeCommands" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#with-docker -->
      <context name="WITH_ctx" attribute="Normal Text" lineEndContext="#stay">
        <WordDetect String="DOCKER" attribute="Command" context="#stay" />
        <WordDetect String="END" attribute="Command" context="#pop" endRegion="WITH" />
        <StringDetect String="--pull" attribute="Command Option" context="#stay" />
        <StringDetect String="--load" attribute="Command Option" context="#stay" />
        <StringDetect String="--compose" attribute="Command Option" context="#stay" />
        <StringDetect String="--service" attribute="Command Option" context="#stay" />
        <StringDetect String="--allow-privileged" attribute="Command Option" context="#stay" />
        <IncludeRules context="RecipeCommands" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#for -->
      <context name="FOR_ctx" attribute="Normal Text" lineEndContext="#stay">
        <WordDetect String="IN" attribute="Command" context="#stay" />
        <WordDetect String="END" attribute="Command" context="#pop" endRegion="FOR" />
        <StringDetect String="--sep" attribute="Command Option" context="#stay" />
        <StringDetect String="--privileged" attribute="Command Option" context="#stay" />
        <StringDetect String="--ssh" attribute="Command Option" context="#stay" />
        <StringDetect String="--no-cache" attribute="Command Option" context="#stay" />
        <StringDetect String="--secret" attribute="Command Option" context="#stay" />
        <IncludeRules context="RecipeCommands" />
      </context>

      <!--
        FROM [options] <target> [build-args]
        FROM DOCKERFILE [options] <context>

        https://docs.earthly.dev/docs/earthfile#from
        https://docs.earthly.dev/docs/earthfile#from-dockerfile
      -->
      <context name="FROM_ctx" attribute="Normal Text" lineEndContext="#pop">
        <WordDetect String="DOCKERFILE" attribute="Command" context="#stay" />

        <!-- Options for the first form -->
        <StringDetect String="--allow-privileged" attribute="Command Option" context="#stay" />
        <StringDetect String="--platform" attribute="Command Option" context="#stay" />

        <!-- Options for the second form -->
        <StringDetect String="-f" attribute="Command Option" context="#stay" />
        <StringDetect String="--target" attribute="Command Option" context="#stay" />

        <IncludeRules context="RecipeContent" />
      </context>

      <!--
        SAVE ARTIFACT
        https://docs.earthly.dev/docs/earthfile#save-artifact

        SAVE IMAGE
        https://docs.earthly.dev/docs/earthfile#save-image
      -->
      <context name="SAVE_ctx" attribute="Normal Text" lineEndContext="#pop">
        <WordDetect String="ARTIFACT" attribute="Command" context="#stay" />
        <WordDetect String="AS" attribute="Command" context="#stay" />
        <WordDetect String="LOCAL" attribute="Command" context="#stay" />
        <WordDetect String="IMAGE" attribute="Command" context="#stay" />

        <!-- Options for the first form -->
        <StringDetect String="--keep-ts" attribute="Command Option" context="#stay" />
        <StringDetect String="--keep-own" attribute="Command Option" context="#stay" />
        <StringDetect String="--if-exists" attribute="Command Option" context="#stay" />
        <StringDetect String="--force" attribute="Command Option" context="#stay" />

        <!-- Options for the second form -->
        <StringDetect String="--cache-hint" attribute="Command Option" context="#stay" />
        <StringDetect String="--cache-from" attribute="Command Option" context="#stay" />
        <StringDetect String="--push" attribute="Command Option" context="#stay" />

        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#run -->
      <context name="RUN_ctx" attribute="Normal Text" lineEndContext="#stay" fallthroughContext="#pop!BashOneLine##Bash">
        <DetectSpaces />
        <LineContinue context="#stay" />
        <DetectChar char="[" attribute="Operator" context="#pop!RUN_exec" />
        <StringDetect String="--push" attribute="Command Option" context="#stay" />
        <StringDetect String="--no-cache" attribute="Command Option" context="#stay" />
        <StringDetect String="--entrypoint" attribute="Command Option" context="#stay" />
        <StringDetect String="--privileged" attribute="Command Option" context="#stay" />
        <StringDetect String="--ssh" attribute="Command Option" context="#stay" />
        <StringDetect String="--secret" attribute="Command Option" context="secret_opt" />
        <StringDetect String="--mount" attribute="Command Option" context="mount_opt" />
        <StringDetect String="--interactive-keep" attribute="Command Option" context="#stay" />
        <StringDetect String="--interactive" attribute="Command Option" context="#stay" />
        <Detect2Chars char="-" char1="-" attribute="Command Option" context="#pop!BashOneLine##Bash" />
      </context>
      <!-- Second form of `RUN` -->
      <context name="RUN_exec" attribute="Normal Text" lineEndContext="#pop">
        <DetectChar char="]" attribute="Operator" context="#pop" />
        <IncludeRules context="RecipeContent" />
      </context>

      <!-- https://docs.earthly.dev/docs/earthfile#if -->
      <context name="IF_ctx" attribute="Normal Text" lineEndContext="#stay">
        <DetectSpaces />
        <LineContinue context="#stay" />

        <StringDetect String="ELSE IF" attribute="Command" context="#stay" />
        <WordDetect String="ELSE" attribute="Command" context="#stay" />
        <WordDetect String="END" attribute="Command" context="#pop" endRegion="IF" />

        <StringDetect String="--privileged" attribute="Command Option" context="#stay" />
        <StringDetect String="--ssh" attribute="Command Option" context="#stay" />
        <StringDetect String="--no-cache" attribute="Command Option" context="#stay" />
        <StringDetect String="--entrypoint" attribute="Command Option" context="#stay" />
        <StringDetect String="--mount" attribute="Command Option" context="mount_opt" />
        <StringDetect String="--secret" attribute="Command Option" context="secret_opt" />
        <!-- start expression in single brackets -->
        <DetectChar char="[" attribute="Operator" context="BracketExpression" />
        <IncludeRules context="RecipeCommands" />
      </context>

      <context name="BracketExpression" attribute="Normal Text" lineEndContext="#pop">
        <DetectChar char="]" attribute="Operator" context="#pop" />
        <AnyChar String="!=" attribute="Operator" context="#stay" />
        <RegExpr String="(&binary_operators;|&unary_operators;)" attribute="Operator" context="#stay" />
        <DetectSpaces />
        <IncludeRules context="RecipeContent" />
      </context>

      <context name="mount_opt" attribute="Command Option" lineEndContext="#stay" fallthroughContext="#pop!mount_arg">
        <DetectSpaces context="#stay" />
      </context>

      <context name="mount_arg" attribute="Command Option" lineEndContext="#stay" fallthroughContext="#pop">
        <keyword String="mount_keys" insensitive="false" attribute="Command Option" context="#stay" />
        <AnyChar String=",=" attribute="Operator" context="#stay" />
        <!--
            ALERT A mount option arg must consume characters up to the next space
            and stay in this context to match other rules. Typically there are characters
            that could be found in file paths...

            NOTE If you see "Normal Text" in the `mount` options, update the String below.

            TODO Any better way?
        -->
        <AnyChar String="/.-" attribute="Command Option" context="#stay" />
        <DetectIdentifier attribute="Command Option" />
        <IncludeRules context="RecipeContent" includeAttrib="true" />
        <DetectSpaces context="#pop" />
      </context>

      <context name="secret_opt" attribute="Normal Text" lineEndContext="#stay" fallthroughContext="#pop!secret_arg">
        <DetectSpaces context="#stay" />
      </context>

      <context name="secret_arg" attribute="Normal Text" lineEndContext="#stay" fallthroughContext="#pop">
        <DetectIdentifier attribute="Command Option" />
        <DetectChar char="=" attribute="Operator" context="#stay" />
        <IncludeRules context="RecipeContent" />
        <DetectSpaces context="#pop" />
      </context>

    </contexts>

    <itemDatas>
      <itemData name="Normal Text"              defStyleNum="dsNormal" spellChecking="false" />
      <itemData name="Command"                  defStyleNum="dsKeyword" bold="true" spellChecking="false" />
      <itemData name="User Defined Command"     defStyleNum="dsFunction" spellChecking="false" />
      <itemData name="Command Option"           defStyleNum="dsAttribute" italic="true" spellChecking="false" />
      <itemData name="Build Arg"                defStyleNum="dsAttribute" italic="true" spellChecking="false" />
      <itemData name="Reference"                defStyleNum="dsExtension" spellChecking="false" />
      <itemData name="Target Name"              defStyleNum="dsImport" spellChecking="false" />
      <itemData name="Operator"                 defStyleNum="dsOperator" spellChecking="false" />
      <itemData name="Artifact Name"            defStyleNum="dsExtension" spellChecking="false" />
      <itemData name="Variable"                 defStyleNum="dsVariable" spellChecking="false" />
      <itemData name="Builtin Variable"         defStyleNum="dsVariable" spellChecking="false" color="#c09050" selColor="#c09050" />
      <itemData name="Internal/Local Variable"  defStyleNum="dsVariable" spellChecking="false" />
      <itemData name="Comment"                  defStyleNum="dsComment" />
      <itemData name="String SingleQ"           defStyleNum="dsString" />
      <itemData name="String DoubleQ"           defStyleNum="dsString" />
      <itemData name="String Escape"            defStyleNum="dsSpecialChar" />
      <itemData name="Integer"                  defStyleNum="dsDecVal" />
    </itemDatas>

  </highlighting>

  <general>
    <comments>
      <comment name="singleLine" start="#" position="afterwhitespace"/>
    </comments>
  </general>

</language>
