Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions antora-ui/src/css/cpp-highlight.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* cpp-highlight.css - Custom C++ syntax highlighting styles
* This replaces highlight.js's C++ highlighting for consistent styling
*/

/* C++ Keywords - blue, bold */
code.cpp-highlight .cpp-keyword,
.doc pre.highlight code.cpp-highlight .cpp-keyword {
color: #00f;
font-weight: bold;
}

/* C++ Strings - dark red */
code.cpp-highlight .cpp-string,
.doc pre.highlight code.cpp-highlight .cpp-string {
color: #a31515;
}

/* C++ Preprocessor directives - purple */
code.cpp-highlight .cpp-preprocessor,
.doc pre.highlight code.cpp-highlight .cpp-preprocessor {
color: #6f008a;
}

/* C++ Comments - green, italic */
code.cpp-highlight .cpp-comment,
.doc pre.highlight code.cpp-highlight .cpp-comment {
color: #008000;
font-style: italic;
}

/* Base text in C++ blocks - plain black (identifiers, function names, etc.) */
code.cpp-highlight,
.doc pre.highlight code.cpp-highlight {
color: inherit;
}
1 change: 1 addition & 0 deletions antora-ui/src/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@import "header.css";
@import "footer.css";
@import "highlight.css";
@import "cpp-highlight.css";
@import "print.css";
@import "tailwindcss/base";
@import "tailwindcss/components";
Expand Down
199 changes: 199 additions & 0 deletions antora-ui/src/js/vendor/cpp-highlight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* cpp-highlight.js - Lightweight C++ syntax highlighter
*
* Categories:
* - keyword : Language keywords (const, while, if, etc.)
* - string : String and character literals
* - preprocessor: Preprocessor directives (#include, #define, etc.)
* - comment : C and C++ style comments
*/

const CppHighlight = (function () {
'use strict'

const KEYWORDS = new Set([
// Storage class
'auto', 'register', 'static', 'extern', 'mutable', 'thread_local',
// Type qualifiers
'const', 'volatile', 'constexpr', 'consteval', 'constinit',
// Type specifiers
'void', 'bool', 'char', 'short', 'int', 'long', 'float', 'double',
'signed', 'unsigned', 'wchar_t', 'char8_t', 'char16_t', 'char32_t',
// Complex types
'class', 'struct', 'union', 'enum', 'typename', 'typedef',
// Control flow
'if', 'else', 'switch', 'case', 'default', 'for', 'while', 'do',
'break', 'continue', 'return', 'goto',
// Exception handling
'try', 'catch', 'throw', 'noexcept',
// OOP
'public', 'private', 'protected', 'virtual', 'override', 'final',
'friend', 'this', 'operator', 'new', 'delete',
// Templates
'template', 'concept', 'requires',
// Namespace
'namespace', 'using',
// Other
'sizeof', 'alignof', 'alignas', 'decltype', 'typeid',
'static_cast', 'dynamic_cast', 'const_cast', 'reinterpret_cast',
'static_assert', 'inline', 'explicit', 'export', 'module', 'import',
'co_await', 'co_yield', 'co_return',
// Literals
'true', 'false', 'nullptr', 'NULL',
])

function escapeHtml (text) {
return text
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
}

function span (cls, content) {
return `<span class="cpp-${cls}">${escapeHtml(content)}</span>`
}

function highlight (code) {
const result = []
let i = 0
const n = code.length

while (i < n) {
// Line comment
if (code[i] === '/' && code[i + 1] === '/') {
let end = i + 2
while (end < n && code[end] !== '\n') end++
result.push(span('comment', code.slice(i, end)))
i = end
continue
}

// Block comment
if (code[i] === '/' && code[i + 1] === '*') {
let end = i + 2
while (end < n - 1 && !(code[end] === '*' && code[end + 1] === '/')) end++
end += 2
result.push(span('comment', code.slice(i, end)))
i = end
continue
}

// Preprocessor directive (at start of line or after whitespace)
if (code[i] === '#') {
// Check if # is at line start (allow leading whitespace)
let checkPos = i - 1
while (checkPos >= 0 && (code[checkPos] === ' ' || code[checkPos] === '\t')) checkPos--
if (checkPos < 0 || code[checkPos] === '\n') {
let end = i + 1
// Handle line continuation with backslash
while (end < n) {
if (code[end] === '\n') {
if (code[end - 1] === '\\') {
end++
continue
}
break
}
end++
}
result.push(span('preprocessor', code.slice(i, end)))
i = end
continue
}
}

// Raw string literal R"delimiter(...)delimiter"
if (code[i] === 'R' && code[i + 1] === '"') {
let delimEnd = i + 2
while (delimEnd < n && code[delimEnd] !== '(') delimEnd++
const delimiter = code.slice(i + 2, delimEnd)
const endMarker = ')' + delimiter + '"'
let end = delimEnd + 1
while (end < n) {
if (code.slice(end, end + endMarker.length) === endMarker) {
end += endMarker.length
break
}
end++
}
result.push(span('string', code.slice(i, end)))
i = end
continue
}

// String literal (with optional prefix)
if (code[i] === '"' ||
((code[i] === 'L' || code[i] === 'u' || code[i] === 'U') && code[i + 1] === '"') ||
(code[i] === 'u' && code[i + 1] === '8' && code[i + 2] === '"')) {
const start = i
if (code[i] === 'u' && code[i + 1] === '8') i += 2
else if (code[i] !== '"') i++
i++ // skip opening quote
while (i < n && code[i] !== '"') {
if (code[i] === '\\' && i + 1 < n) i += 2
else i++
}
i++ // skip closing quote
result.push(span('string', code.slice(start, i)))
continue
}

// Character literal
if (code[i] === '\'' ||
((code[i] === 'L' || code[i] === 'u' || code[i] === 'U') && code[i + 1] === '\'') ||
(code[i] === 'u' && code[i + 1] === '8' && code[i + 2] === '\'')) {
const start = i
if (code[i] === 'u' && code[i + 1] === '8') i += 2
else if (code[i] !== '\'') i++
i++ // skip opening quote
while (i < n && code[i] !== '\'') {
if (code[i] === '\\' && i + 1 < n) i += 2
else i++
}
i++ // skip closing quote
result.push(span('string', code.slice(start, i)))
continue
}

// Identifier or keyword
if (/[a-zA-Z_]/.test(code[i])) {
let end = i + 1
while (end < n && /[a-zA-Z0-9_]/.test(code[end])) end++
const word = code.slice(i, end)
if (KEYWORDS.has(word)) {
result.push(span('keyword', word))
} else {
result.push(escapeHtml(word))
}
i = end
continue
}

// Default: single character
result.push(escapeHtml(code[i]))
i++
}

return result.join('')
}

function highlightElement (el) {
el.innerHTML = highlight(el.textContent)
}

function highlightAll (selector = 'code.cpp, code.c++, pre.cpp, pre.c++') {
document.querySelectorAll(selector).forEach(highlightElement)
}

return {
highlight,
highlightElement,
highlightAll,
KEYWORDS,
}
})()

// CommonJS / ES module support
if (typeof module !== 'undefined' && module.exports) {
module.exports = CppHighlight
}
83 changes: 82 additions & 1 deletion antora-ui/src/js/vendor/highlight.bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,92 @@
'use strict'

var hljs = require('highlight.js/lib/common')
var CppHighlight = require('./cpp-highlight')

// Only register languages not included in common bundle
hljs.registerLanguage('cmake', require('highlight.js/lib/languages/cmake'))

hljs.highlightAll()
// Replace C++ highlighting AFTER highlight.js processes blocks
// Let hljs work initially, then replace C++ blocks with custom highlighter
function processCppBlocks () {
// Selectors for C++ code blocks that highlight.js has already processed
var cppSelectors = [
'code.language-cpp.hljs',
'code.language-c++.hljs',
'code[data-lang="cpp"].hljs',
'code[data-lang="c++"].hljs',
'.doc pre.highlight code[data-lang="cpp"].hljs',
'.doc pre.highlight code[data-lang="c++"].hljs',
]

var processedCount = 0

cppSelectors.forEach(function (selector) {
try {
document.querySelectorAll(selector).forEach(function (el) {
// Skip if already processed
if (el.classList.contains('cpp-highlight')) return

// Replace highlight.js's C++ highlighting with our custom highlighter
// This gives us full control over C++ syntax highlighting
CppHighlight.highlightElement(el)

// Mark as processed with our custom highlighter
el.classList.add('cpp-highlight')
processedCount++
})
} catch (e) {
console.warn('cpp-highlight error:', selector, e)
}
})

if (processedCount > 0) {
console.log('cpp-highlight: Replaced ' + processedCount + ' C++ code blocks')
}
}

// Process C++ blocks after highlight.js runs
function initHighlighting () {
// First, let highlight.js process everything
hljs.highlightAll()

// Then, replace C++ blocks with our custom highlighter
// Use setTimeout to ensure highlight.js is completely done
setTimeout(function () {
processCppBlocks()
}, 0)
}

// Process when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initHighlighting)
} else {
// DOM already loaded
initHighlighting()
}

// Also use MutationObserver to catch dynamically added content
// Process C++ blocks after highlight.js processes new content
if (typeof window.MutationObserver !== 'undefined') {
var observer = new window.MutationObserver(function (mutations) {
var shouldProcess = false
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length > 0) {
shouldProcess = true
}
})
if (shouldProcess) {
// Wait a bit for highlight.js to process new content
setTimeout(function () {
processCppBlocks()
}, 100)
}
})
observer.observe(document.body || document.documentElement, {
childList: true,
subtree: true,
})
}

window.hljs = hljs
})()
Loading