Skip to content

Commit

Permalink
enh(cpp) Highlight all function dispatches (#3005)
Browse files Browse the repository at this point in the history
* convert cpp built-ins to relevance hints (and match ALL dispatches)
* fix arduino to use function dispatch also
* document the new keywords `_ident` behavior
  • Loading branch information
joshgoebel committed Mar 7, 2021
1 parent 9d17540 commit d2f3ab5
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ New Languages:

Language grammar improvements:

- enh(cpp) Highlight all function dispatches (#3005) [Josh Goebel][]
- enh(python) support type hints and better type support (#2972) [Josh Goebel][]
- enh(gml) Add additional GML 2.3 keywords (#2984) [xDGameStudios][]
- fix(cpp) constructor support for initializers (#3001) [Josh Goebel][]
Expand Down
6 changes: 4 additions & 2 deletions docs/language-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ object, each property of which defines its own group of keywords:
{
keywords: {
keyword: 'else for if while',
literal: ['false','true','null']
literal: ['false','true','null'],
_relevance_only: 'one two three four'
}
}

The group name becomes the class name in the generated markup, enabling different
theming for different kinds of keywords.
theming for different kinds of keywords. Any property starting with a ``_`` will
only use those keywords to increase relevance, they will not be highlighted.

To detect keywords, highlight.js breaks the processed chunk of code into separate
words — a process called lexing. By default, "words" are matched with the regexp
Expand Down
10 changes: 8 additions & 2 deletions src/highlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,14 @@ const HLJS = function(hljs) {
buf = "";

relevance += keywordRelevance;
const cssClass = language.classNameAliases[kind] || kind;
emitter.addKeyword(match[0], cssClass);
if (kind.startsWith("_")) {
// _ implied for relevance only, do not highlight
// by applying a class name
buf += match[0];
} else {
const cssClass = language.classNameAliases[kind] || kind;
emitter.addKeyword(match[0], cssClass);
}
} else {
buf += match[0];
}
Expand Down
6 changes: 4 additions & 2 deletions src/languages/arduino.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export default function(hljs) {
keyword:
'boolean byte word String',
built_in:
'setup loop ' +
'KeyboardController MouseController SoftwareSerial ' +
'EthernetServer EthernetClient LiquidCrystal ' +
'RobotControl GSMVoiceCall EthernetUDP EsploraTFT ' +
Expand All @@ -24,7 +23,9 @@ export default function(hljs) {
'WiFiUDP GSM_SMS Mailbox USBHost Firmata PImage ' +
'Client Server GSMPIN FileIO Bridge Serial ' +
'EEPROM Stream Mouse Audio Servo File Task ' +
'GPRS WiFi Wire TFT GSM SPI SD ' +
'GPRS WiFi Wire TFT GSM SPI SD ',
_:
'setup loop ' +
'runShellCommandAsynchronously analogWriteResolution ' +
'retrieveCallingNumber printFirmwareVersion ' +
'analogReadResolution sendDigitalPortPair ' +
Expand Down Expand Up @@ -102,6 +103,7 @@ export default function(hljs) {
kws.keyword += ' ' + ARDUINO_KW.keyword;
kws.literal += ' ' + ARDUINO_KW.literal;
kws.built_in += ' ' + ARDUINO_KW.built_in;
kws._ += ' ' + ARDUINO_KW._;

ARDUINO.name = 'Arduino';
ARDUINO.aliases = ['ino'];
Expand Down
147 changes: 138 additions & 9 deletions src/languages/cpp.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,122 @@ export default function(hljs) {

const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';

const COMMON_CPP_HINTS = [
'asin',
'atan2',
'atan',
'calloc',
'ceil',
'cosh',
'cos',
'exit',
'exp',
'fabs',
'floor',
'fmod',
'fprintf',
'fputs',
'free',
'frexp',
'auto_ptr',
'deque',
'list',
'queue',
'stack',
'vector',
'map',
'set',
'pair',
'bitset',
'multiset',
'multimap',
'unordered_set',
'fscanf',
'future',
'isalnum',
'isalpha',
'iscntrl',
'isdigit',
'isgraph',
'islower',
'isprint',
'ispunct',
'isspace',
'isupper',
'isxdigit',
'tolower',
'toupper',
'labs',
'ldexp',
'log10',
'log',
'malloc',
'realloc',
'memchr',
'memcmp',
'memcpy',
'memset',
'modf',
'pow',
'printf',
'putchar',
'puts',
'scanf',
'sinh',
'sin',
'snprintf',
'sprintf',
'sqrt',
'sscanf',
'strcat',
'strchr',
'strcmp',
'strcpy',
'strcspn',
'strlen',
'strncat',
'strncmp',
'strncpy',
'strpbrk',
'strrchr',
'strspn',
'strstr',
'tanh',
'tan',
'unordered_map',
'unordered_multiset',
'unordered_multimap',
'priority_queue',
'make_pair',
'array',
'shared_ptr',
'abort',
'terminate',
'abs',
'acos',
'vfprintf',
'vprintf',
'vsprintf',
'endl',
'initializer_list',
'unique_ptr',
'complex',
'imaginary',
'std',
'string',
'wstring',
'cin',
'cout',
'cerr',
'clog',
'stdin',
'stdout',
'stderr',
'stringstream',
'istringstream',
'ostringstream'
];

const CPP_KEYWORDS = {
keyword: 'int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof ' +
'dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace ' +
Expand All @@ -120,19 +236,27 @@ export default function(hljs) {
'atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong ' +
'atomic_ullong new throw return ' +
'and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq',
built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream ' +
'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set ' +
'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos ' +
'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp ' +
'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper ' +
'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow ' +
'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp ' +
'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan ' +
'vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary',
built_in: '_Bool _Complex _Imaginary',
_relevance_hints: COMMON_CPP_HINTS,
literal: 'true false nullptr NULL'
};

const FUNCTION_DISPATCH = {
className: "function.dispatch",
relevance: 0,
keywords: CPP_KEYWORDS,
begin: regex.concat(
/\b/,
/(?!decltype)/,
/(?!if)/,
/(?!for)/,
/(?!while)/,
hljs.IDENT_RE,
regex.lookahead(/\s*\(/))
};

const EXPRESSION_CONTAINS = [
FUNCTION_DISPATCH,
PREPROCESSOR,
CPP_PRIMITIVE_TYPES,
C_LINE_COMMENT_MODE,
Expand All @@ -141,6 +265,7 @@ export default function(hljs) {
STRINGS
];


const EXPRESSION_CONTEXT = {
// This mode covers expression context where we can't expect a function
// definition and shouldn't highlight anything that looks like one:
Expand Down Expand Up @@ -256,9 +381,13 @@ export default function(hljs) {
],
keywords: CPP_KEYWORDS,
illegal: '</',
classNameAliases: {
"function.dispatch": "built_in"
},
contains: [].concat(
EXPRESSION_CONTEXT,
FUNCTION_DECLARATION,
FUNCTION_DISPATCH,
EXPRESSION_CONTAINS,
[
PREPROCESSOR,
Expand Down
7 changes: 4 additions & 3 deletions test/markup/cpp/function-declarations.expect.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<span class="hljs-function"><span class="hljs-keyword">decltype</span>(<span class="hljs-keyword">auto</span>) <span class="hljs-title">look_up_a_string_1</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> lookup1(); }
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">look_up_a_string_2</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> lookup2(); }
<span class="hljs-function"><span class="hljs-keyword">decltype</span>(<span class="hljs-keyword">auto</span>) <span class="hljs-title">look_up_a_string_1</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-built_in">lookup1</span>(); }
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">look_up_a_string_2</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-built_in">lookup2</span>(); }
<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-keyword">void</span> <span class="hljs-title">A::showB</span><span class="hljs-params">(B x)</span> </span>{}
<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showB</span><span class="hljs-params">(B x)</span> </span>{}
<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showB</span><span class="hljs-params">(B::SomeType x)</span> </span>{}
Expand All @@ -17,7 +17,8 @@
<span class="hljs-function"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">typename</span> T...&gt;
<span class="hljs-keyword">void</span> <span class="hljs-title">foo</span><span class="hljs-params">(T... args)</span> </span>{}

test();
<span class="hljs-built_in">test</span>();

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">A</span><span class="hljs-params">()</span>: a(<span class="hljs-number">10</span>) {</span>}
<span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">A</span><span class="hljs-params">()</span>: a(<span class="hljs-number">10</span>) {</span>}

10 changes: 5 additions & 5 deletions test/markup/cpp/function-title.expect.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{
A a = <span class="hljs-keyword">new</span> A();
<span class="hljs-keyword">int</span> b = b * sum(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);
<span class="hljs-keyword">if</span> (a-&gt;check1())
A a = <span class="hljs-keyword">new</span> <span class="hljs-built_in">A</span>();
<span class="hljs-keyword">int</span> b = b * <span class="hljs-built_in">sum</span>(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);
<span class="hljs-keyword">if</span> (a-&gt;<span class="hljs-built_in">check1</span>())
<span class="hljs-keyword">return</span> <span class="hljs-number">3</span>;
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (a-&gt;check2())
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (a-&gt;<span class="hljs-built_in">check2</span>())
<span class="hljs-keyword">return</span> <span class="hljs-number">4</span>;
<span class="hljs-keyword">return</span> a-&gt;result();
<span class="hljs-keyword">return</span> a-&gt;<span class="hljs-built_in">result</span>();
}
4 changes: 2 additions & 2 deletions test/markup/cpp/preprocessor.expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@

<span class="hljs-keyword">if</span> (p) {
<span class="hljs-meta">#<span class="hljs-meta-keyword">ifdef</span> DEBUG</span>
onething();
<span class="hljs-built_in">onething</span>();
<span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (errno) {
<span class="hljs-meta">#<span class="hljs-meta-keyword">ifdef</span> DEBUG</span>
anotherthing();
<span class="hljs-built_in">anotherthing</span>();
<span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span>
}

Expand Down
8 changes: 4 additions & 4 deletions test/markup/cpp/template_complexity.expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

<span class="hljs-keyword">namespace</span> impl {
<span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">typename</span> T&gt;
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">is_streamable</span>&lt;</span>T, <span class="hljs-built_in">std</span>::<span class="hljs-keyword">void_t</span>&lt;<span class="hljs-keyword">decltype</span>(<span class="hljs-built_in">std</span>::declval&lt;<span class="hljs-built_in">std</span>::wostream &amp;&gt;() &lt;&lt; <span class="hljs-built_in">std</span>::declval&lt;T&gt;())&gt;&gt; : <span class="hljs-built_in">std</span>::true_type { };
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">is_streamable</span>&lt;</span>T, std::<span class="hljs-keyword">void_t</span>&lt;<span class="hljs-keyword">decltype</span>(std::declval&lt;std::wostream &amp;&gt;() &lt;&lt; std::declval&lt;T&gt;())&gt;&gt; : std::true_type { };
}

<span class="hljs-comment">// Disable overload for already valid operands.</span>
<span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">T</span>, <span class="hljs-keyword">class</span> =</span> <span class="hljs-built_in">std</span>::<span class="hljs-keyword">enable_if_t</span>&lt;!impl::is_streamable_v&lt;<span class="hljs-keyword">const</span> T &amp;&gt; &amp;&amp; <span class="hljs-built_in">std</span>::is_convertible_v&lt;<span class="hljs-keyword">const</span> T &amp;, <span class="hljs-built_in">std</span>::wstring_view&gt;&gt;&gt;
<span class="hljs-built_in">std</span>::wostream &amp;<span class="hljs-keyword">operator</span> &lt;&lt;(<span class="hljs-built_in">std</span>::wostream &amp;stream, <span class="hljs-keyword">const</span> T &amp;thing)
<span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">T</span>, <span class="hljs-keyword">class</span> =</span> std::<span class="hljs-keyword">enable_if_t</span>&lt;!impl::is_streamable_v&lt;<span class="hljs-keyword">const</span> T &amp;&gt; &amp;&amp; std::is_convertible_v&lt;<span class="hljs-keyword">const</span> T &amp;, std::wstring_view&gt;&gt;&gt;
std::wostream &amp;<span class="hljs-keyword">operator</span> &lt;&lt;(std::wostream &amp;stream, <span class="hljs-keyword">const</span> T &amp;thing)
{
<span class="hljs-keyword">return</span> stream &lt;&lt; <span class="hljs-keyword">static_cast</span>&lt;<span class="hljs-built_in">std</span>::wstring_view&gt;(thing);
<span class="hljs-keyword">return</span> stream &lt;&lt; <span class="hljs-keyword">static_cast</span>&lt;std::wstring_view&gt;(thing);
}

<span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-keyword">struct</span> <span class="hljs-title">DataHolder</span> {</span> };
Expand Down

0 comments on commit d2f3ab5

Please sign in to comment.