diff --git a/CHANGES.md b/CHANGES.md index 016bc0bc76..78eb8f7fc4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ Core Grammars: - enh(dos) add `batch` as an alias, issue #4395 [Hashim Khan][] - fix(lisp) preserve highlighting after quoted multiplication expressions [arturict][] - fix(rust) recognize `\\` and `\"` char-literal escapes so highlighting doesn't leak, issue #4351 [Sarath Francis][] +- fix(rust) reuse the string rules inside attributes so raw and byte strings are highlighted there, issue #3817 [Maksim Zhukau][] - fix(cmake) only highlight standalone numbers, not digits that begin an identifier (e.g. `3rdparty`), issue #4170 [MarkXian][] - fix(cpp) require a word boundary before numeric literals so digits inside identifiers aren't highlighted as numbers, issue #4231 [Mark Xian][] - fix(c) only match real `atomic_*` type names, not C11 atomic functions, issue #3837 [MarkXian][] @@ -43,6 +44,7 @@ CONTRIBUTORS [Nicolas Le Cam]: https://github.com/KuSh [Konstantin Baltsat]: https://github.com/Baltsat [David Pavlovschii]: https://github.com/davidpavlovschi +[Maksim Zhukau]: https://github.com/MaksZhukov [Pablo]: https://github.com/MsfPablo [Jayesh Bhade]: https://github.com/Jaybhade [Hirse]: https://github.com/Hirse diff --git a/src/languages/rust.js b/src/languages/rust.js index 633ec69bde..a98e89b62f 100644 --- a/src/languages/rust.js +++ b/src/languages/rust.js @@ -157,6 +157,26 @@ export default function(hljs) { "assert_ne!", "debug_assert_ne!" ]; + const QUOTE_STRING = hljs.inherit(hljs.QUOTE_STRING_MODE, { + begin: /b?"/, + illegal: null + }); + const RAW_STRING = { + scope: 'string', + // rustc caps raw string delimiters at 255 hashes + begin: /b?r(#{0,255})"(.|\n)*?"\1(?!#)/ + }; + const CHARACTER = { + scope: 'string', + begin: /b?'/, + end: /'/, + contains: [ + { + scope: "char.escape", + match: /\\('|"|\\|\w|x\w{2}|u\w{4}|U\w{8})/ + } + ] + }; const TYPES = [ "i8", "i16", @@ -197,31 +217,14 @@ export default function(hljs) { contains: [ hljs.C_LINE_COMMENT_MODE, hljs.COMMENT('/\\*', '\\*/', { contains: [ 'self' ] }), - hljs.inherit(hljs.QUOTE_STRING_MODE, { - begin: /b?"/, - illegal: null - }), + QUOTE_STRING, { scope: 'symbol', // negative lookahead to avoid matching `'` begin: /'[a-zA-Z_][a-zA-Z0-9_]*(?!')/ }, - { - scope: 'string', - variants: [ - { begin: /b?r(#*)"(.|\n)*?"\1(?!#)/ }, - { - begin: /b?'/, - end: /'/, - contains: [ - { - scope: "char.escape", - match: /\\('|"|\\|\w|x\w{2}|u\w{4}|U\w{8})/ - } - ] - } - ] - }, + RAW_STRING, + CHARACTER, { scope: 'number', variants: [ @@ -260,14 +263,10 @@ export default function(hljs) { begin: '#!?\\[', end: '\\]', contains: [ - { - scope: 'string', - begin: /"/, - end: /"/, - contains: [ - hljs.BACKSLASH_ESCAPE - ] - } + // attributes hold arbitrary token trees, so any string literal + // that is valid elsewhere is valid here too + QUOTE_STRING, + RAW_STRING ] }, { diff --git a/test/markup/rust/strings.expect.txt b/test/markup/rust/strings.expect.txt index 6ddd0da66e..26f1188722 100644 --- a/test/markup/rust/strings.expect.txt +++ b/test/markup/rust/strings.expect.txt @@ -22,5 +22,11 @@ br" "; br#"hello"#; br##"foo"##; +r################"many hashes"################; #[error("\" appears in a string")] +#[doc = r#"a "quoted" word"#] +#[doc = b"bytes"] +#[doc = r##"multi +line "# raw"##] +#[foo(Bar<'a>)] diff --git a/test/markup/rust/strings.txt b/test/markup/rust/strings.txt index e4d85db470..502deac7de 100644 --- a/test/markup/rust/strings.txt +++ b/test/markup/rust/strings.txt @@ -22,5 +22,11 @@ r##" "### br" "; br#"hello"#; br##"foo"##; +r################"many hashes"################; #[error("\" appears in a string")] +#[doc = r#"a "quoted" word"#] +#[doc = b"bytes"] +#[doc = r##"multi +line "# raw"##] +#[foo(Bar<'a>)]