diff --git a/CHANGES.md b/CHANGES.md index 7e3e82de81..cdf11535de 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,10 @@ Language Improvements: - (ini) support TOML arrays, clean up grammar (#2335) [Josh Goebel][] - (vbnet) add nameof operator to the keywords (#2329) [Youssef Victor][] - (stan) updated with improved coverage of language keywords and patterns. (#1829) [Jeffrey Arnold][] +- enh(cpp) Detect namespaced function types (`A::typeName func(...)`) (#2332) [Josh Goebel][] +- enh(cpp) Detect namespaced functions also (`A::functionName`) (#2332) [Josh Goebel][] +- enh(cpp) Properly detect decltype(auto) (#2332) [Josh Goebel][] +- enh(cpp) recognize primitive types (`int8_t`, etc.) as function types (#2332) [Josh Goebel][] Developer Tools: diff --git a/src/languages/cpp.js b/src/languages/cpp.js index 38a0335a18..a6849e47cb 100644 --- a/src/languages/cpp.js +++ b/src/languages/cpp.js @@ -7,6 +7,16 @@ Website: https://isocpp.org */ function(hljs) { + function optional(s) { + return '(?:' + s + ')?'; + } + var DECLTYPE_AUTO_RE = 'decltype\\(auto\\)' + var NAMESPACE_RE = '[a-zA-Z_]\\w*::' + var TEMPLATE_ARGUMENT_RE = '<.*?>'; + var FUNCTION_TYPE_RE = '(' + + DECLTYPE_AUTO_RE + '|' + + optional(NAMESPACE_RE) +'[a-zA-Z_]\\w*' + optional(TEMPLATE_ARGUMENT_RE) + + ')'; var CPP_PRIMITIVE_TYPES = { className: 'keyword', begin: '\\b[a-z\\d_]*_t\\b' @@ -64,7 +74,13 @@ function(hljs) { ] }; - var FUNCTION_TITLE = hljs.IDENT_RE + '\\s*\\('; + var TITLE_MODE = { + className: 'title', + begin: optional(NAMESPACE_RE) + hljs.IDENT_RE, + relevance: 0 + }; + + var FUNCTION_TITLE = optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\('; var CPP_KEYWORDS = { keyword: 'int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof ' + @@ -99,86 +115,99 @@ function(hljs) { STRINGS ]; - return { - aliases: ['c', 'cc', 'h', 'c++', 'h++', 'hpp', 'hh', 'hxx', 'cxx'], + var EXPRESSION_CONTEXT = { + // This mode covers expression context where we can't expect a function + // definition and shouldn't highlight anything that looks like one: + // `return some()`, `else if()`, `(x*sum(1, 2))` + variants: [ + {begin: /=/, end: /;/}, + {begin: /\(/, end: /\)/}, + {beginKeywords: 'new throw return else', end: /;/} + ], keywords: CPP_KEYWORDS, - illegal: '', + begin: /\(/, end: /\)/, keywords: CPP_KEYWORDS, - contains: ['self', CPP_PRIMITIVE_TYPES] - }, - { - begin: hljs.IDENT_RE + '::', - keywords: CPP_KEYWORDS + contains: EXPRESSION_CONTAINS.concat(['self']), + relevance: 0 + } + ]), + relevance: 0 + }; + + var FUNCTION_DECLARATION = { + className: 'function', + begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE, + returnBegin: true, end: /[{;=]/, + excludeEnd: true, + keywords: CPP_KEYWORDS, + illegal: /[^\w\s\*&:<>]/, + contains: [ + + { // to prevent it from being confused as the function title + begin: DECLTYPE_AUTO_RE, + keywords: CPP_KEYWORDS, + relevance: 0, }, { - // This mode covers expression context where we can't expect a function - // definition and shouldn't highlight anything that looks like one: - // `return some()`, `else if()`, `(x*sum(1, 2))` - variants: [ - {begin: /=/, end: /;/}, - {begin: /\(/, end: /\)/}, - {beginKeywords: 'new throw return else', end: /;/} - ], - keywords: CPP_KEYWORDS, - contains: EXPRESSION_CONTAINS.concat([ - { - begin: /\(/, end: /\)/, - keywords: CPP_KEYWORDS, - contains: EXPRESSION_CONTAINS.concat(['self']), - relevance: 0 - } - ]), + begin: FUNCTION_TITLE, returnBegin: true, + contains: [TITLE_MODE], relevance: 0 }, { - className: 'function', - begin: '(' + hljs.IDENT_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE, - returnBegin: true, end: /[{;=]/, - excludeEnd: true, + className: 'params', + begin: /\(/, end: /\)/, keywords: CPP_KEYWORDS, - illegal: /[^\w\s\*&]/, + relevance: 0, contains: [ + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + CPP_PRIMITIVE_TYPES, + // Count matching parentheses. { - begin: FUNCTION_TITLE, returnBegin: true, - contains: [hljs.TITLE_MODE], - relevance: 0 - }, - { - className: 'params', begin: /\(/, end: /\)/, keywords: CPP_KEYWORDS, relevance: 0, contains: [ + 'self', hljs.C_LINE_COMMENT_MODE, hljs.C_BLOCK_COMMENT_MODE, STRINGS, NUMBERS, - CPP_PRIMITIVE_TYPES, - // Count matching parentheses. - { - begin: /\(/, end: /\)/, - keywords: CPP_KEYWORDS, - relevance: 0, - contains: [ - 'self', - hljs.C_LINE_COMMENT_MODE, - hljs.C_BLOCK_COMMENT_MODE, - STRINGS, - NUMBERS, - CPP_PRIMITIVE_TYPES - ] - } + CPP_PRIMITIVE_TYPES ] - }, - hljs.C_LINE_COMMENT_MODE, - hljs.C_BLOCK_COMMENT_MODE, - PREPROCESSOR + } ] }, + CPP_PRIMITIVE_TYPES, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + PREPROCESSOR + ] + }; + + return { + aliases: ['c', 'cc', 'h', 'c++', 'h++', 'hpp', 'hh', 'hxx', 'cxx'], + keywords: CPP_KEYWORDS, + illegal: '', + keywords: CPP_KEYWORDS, + contains: ['self', CPP_PRIMITIVE_TYPES] + }, + { + begin: hljs.IDENT_RE + '::', + keywords: CPP_KEYWORDS + }, { className: 'class', beginKeywords: 'class struct', end: /[{;:]/, diff --git a/test/markup/cpp/function-declarations.expect.txt b/test/markup/cpp/function-declarations.expect.txt new file mode 100644 index 0000000000..5189214025 --- /dev/null +++ b/test/markup/cpp/function-declarations.expect.txt @@ -0,0 +1,16 @@ +decltype(auto) look_up_a_string_1() { return lookup1(); } +void look_up_a_string_2() { return lookup2(); } +friend void A::showB(B x) {} +friend void showB(B x) {} +friend void showB(B::SomeType x) {} +inline int add(int a, int b) {} +int8t Get_Tile_Value() {} + +int8_t Get_Tile_Value() {} + +B::type test() {}; + +// template +boost::optional<application> handle_key(application state, key_code key, coord size); + +test(); diff --git a/test/markup/cpp/function-declarations.txt b/test/markup/cpp/function-declarations.txt new file mode 100644 index 0000000000..d196f5ca83 --- /dev/null +++ b/test/markup/cpp/function-declarations.txt @@ -0,0 +1,16 @@ +decltype(auto) look_up_a_string_1() { return lookup1(); } +void look_up_a_string_2() { return lookup2(); } +friend void A::showB(B x) {} +friend void showB(B x) {} +friend void showB(B::SomeType x) {} +inline int add(int a, int b) {} +int8t Get_Tile_Value() {} + +int8_t Get_Tile_Value() {} + +B::type test() {}; + +// template +boost::optional handle_key(application state, key_code key, coord size); + +test();