From b46a98bfae305060b66a78f4908b154ba9d79367 Mon Sep 17 00:00:00 2001 From: Deepak kudi Date: Thu, 4 Jun 2026 12:12:23 +0530 Subject: [PATCH] fix(bash): keep heredoc continuations highlighted --- CHANGES.md | 2 + src/languages/bash.js | 71 ++++++++++++------- .../bash/heredoc-continuation.expect.txt | 3 + test/markup/bash/heredoc-continuation.txt | 3 + test/markup/bash/strings.expect.txt | 2 +- 5 files changed, 56 insertions(+), 25 deletions(-) create mode 100644 test/markup/bash/heredoc-continuation.expect.txt create mode 100644 test/markup/bash/heredoc-continuation.txt diff --git a/CHANGES.md b/CHANGES.md index b1413c29a5..17e3e566ff 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ New Grammars: Core Grammars: +- fix(bash) keep heredoc continuation commands outside the string span, issue #4377 [puneetdixit200][] - fix(javascript) correctly highlight 'for await' again [wolfgang42][] - enh(csp) add missing directives / keywords from MDN (7 more) [Max Liashuk][] - enh(ada) add new `parallel` keyword, allow `[]` for Ada 2022 [Max Reznik][] @@ -55,6 +56,7 @@ CONTRIBUTORS [te-ing]: https://github.com/te-ing [Anthony Martin]: https://github.com/anthony-c-martin [NriotHrreion]: https://github.com/NriotHrreion +[puneetdixit200]: https://github.com/puneetdixit200 ## Version 11.11.1 diff --git a/src/languages/bash.js b/src/languages/bash.js index 44f9beba97..2e101cc761 100644 --- a/src/languages/bash.js +++ b/src/languages/bash.js @@ -50,16 +50,6 @@ export default function(hljs) { } } ); - const HERE_DOC = { - begin: /<<-?\s*(?=\w+)/, - starts: { contains: [ - hljs.END_SAME_AS_BEGIN({ - begin: /(\w+)/, - end: /(\w+)/, - className: 'string' - }) - ] } - }; const QUOTE_STRING = { className: 'string', begin: /"/, @@ -368,6 +358,52 @@ export default function(hljs) { "whoami", "yes" ]; + const BASH_KEYWORDS = { + $pattern: /\b[a-z][a-z0-9._-]+\b/, + keyword: KEYWORDS, + literal: LITERALS, + built_in: [ + ...SHELL_BUILT_INS, + ...BASH_BUILT_INS, + // Shell modifiers + "set", + "shopt", + ...ZSH_BUILT_INS, + ...GNU_CORE_UTILS + ] + }; + let heredocDelimiter = ""; + const HERE_DOC_BODY = { + className: 'string', + begin: /\n/, + end: /^\t*(\w+)$/m, + endsParent: true, + 'on:end': (m, resp) => { + if (m[1] !== heredocDelimiter) resp.ignoreMatch(); + } + }; + const HERE_DOC = { + begin: /<<-?\s*(\w+)/, + 'on:begin': (m) => { heredocDelimiter = m[1]; }, + end: /\n/, + returnEnd: true, + keywords: BASH_KEYWORDS, + contains: [ + ARITHMETIC, + COMMENT, + PATH_MODE, + QUOTE_STRING, + ESCAPED_QUOTE, + APOS_STRING, + ESCAPED_APOS, + VAR + ], + starts: { + contains: [ + HERE_DOC_BODY + ] + } + }; return { name: 'Bash', @@ -375,20 +411,7 @@ export default function(hljs) { 'sh', 'zsh' ], - keywords: { - $pattern: /\b[a-z][a-z0-9._-]+\b/, - keyword: KEYWORDS, - literal: LITERALS, - built_in: [ - ...SHELL_BUILT_INS, - ...BASH_BUILT_INS, - // Shell modifiers - "set", - "shopt", - ...ZSH_BUILT_INS, - ...GNU_CORE_UTILS - ] - }, + keywords: BASH_KEYWORDS, contains: [ KNOWN_SHEBANG, // to catch known shells and boost relevancy hljs.SHEBANG(), // to catch unknown shells but still highlight the shebang diff --git a/test/markup/bash/heredoc-continuation.expect.txt b/test/markup/bash/heredoc-continuation.expect.txt new file mode 100644 index 0000000000..84ffa1b9cb --- /dev/null +++ b/test/markup/bash/heredoc-continuation.expect.txt @@ -0,0 +1,3 @@ +echo "ok" <<-EOF | cat + Hello +EOF diff --git a/test/markup/bash/heredoc-continuation.txt b/test/markup/bash/heredoc-continuation.txt new file mode 100644 index 0000000000..4d12bc6f44 --- /dev/null +++ b/test/markup/bash/heredoc-continuation.txt @@ -0,0 +1,3 @@ +echo "ok" <<-EOF | cat + Hello +EOF diff --git a/test/markup/bash/strings.expect.txt b/test/markup/bash/strings.expect.txt index b86c42b509..2928d0c95d 100644 --- a/test/markup/bash/strings.expect.txt +++ b/test/markup/bash/strings.expect.txt @@ -2,7 +2,7 @@ SCRIPT_DIR="$( cd "$SCRIPT_DIR/../src/main/resources/tls" ROOT_DIR="$SCRIPT_DIR/.." -jshell -s - << EOF +jshell -s - << EOF System.out.printf("Procs: %s%n", getdata()) EOF