OhHighMark 👋
A Ruby library for syntax highlighting markdown code with beautiful, customizable output.
OhHighMark provides colorful and readable markdown syntax visualization by tokenizing and rendering markdown with appropriate CSS classes. It displays each line in a table row with line numbers, ensuring perfect alignment and preserving all whitespace.
Overview
Key Features
- Table-based layout - Each line in its own table row with separate cells for line numbers and code
- Perfect alignment - Line numbers stay aligned with code content, even with long lines
-
Whitespace preservation - Uses
white-space: preto maintain exact spacing and indentation - Non-selectable line numbers - Prevents copy/paste issues
- Comprehensive markdown support - Headings, text formatting, code, links, lists, tables, quotes, and more
- Inline markdown in lists - Bold, italic, links, and other inline syntax work within list items
- Customizable styling - Pre-built CSS with CSS variables for easy theming
-
Semantic HTML - Clean, semantic markup with
data-line-numberon rows - Flexible rules - Customizable tokenization rules via DSL
Supported Markdown Syntax
OhHighMark supports all standard markdown elements:
Text Formatting:
-
Bold:
**text** -
Italic:
_text_ -
Bold-Italic:
***text*** -
Strikethrough:~~text~~
Headings: # H1 through ###### H6
Code:
- Inline:
`code` - Fenced blocks:
```...```
Links:
- Standard:
[text](url) - Auto-links:
<http://url>
Lists:
- Unordered:
- item,* item,+ item - Nested:
- nested item -
With inline markdown:
- **bold** with [link](url)
Tables:
| Column 1 | Column 2 |
| -------- | -------- |
| Value 1 | Value 2 |Other:
- Horizontal rules:
--- - Block quotes:
> quote - Escaped characters:
\*,\[,\],\\
Installation
Add to your Gemfile:
gem 'ohhighmark'Then run:
$ bundle installOr install directly:
$ gem install ohhighmarkUsage
Basic Usage
require 'ohhighmark'
# Use the helper in your views (Rails, Middleman, etc.)
include OhHighMark::Helper
# In your ERB view:
<%= highlight_markdown do %>
# Your Markdown Here
This is **bold** and this is _italic_.
- List item with [link](https://example.com)
- Item with `inline code`
<% end %>Direct API Usage
require 'ohhighmark'
markdown = <<~MD
# Welcome
This is **bold** and ~~strikethrough~~.
MD
# Create highlighter and process
highlighter = OhHighMark::Highlighter.new
html_output = highlighter.process_lines_with_linenums(markdown)Advanced: Custom Rules
# Define custom markdown rules
ruleset = OhHighMark::RuleSet.new
OhHighMark::MarkdownRules.apply(ruleset)
# Add custom rules if needed
ruleset.add(:custom_pattern, /your_regex/, :inline)
# Create tokenizer and renderer
tokenizer = OhHighMark::Tokenizer.new(ruleset.rules)
tokens = tokenizer.tokenize(markdown_text)
renderer = OhHighMark::Renderer.new
html = renderer.render(tokens)Styling
OhHighMark includes a pre-built CSS stylesheet with CSS custom properties (CSS variables) for easy customization.
Including the Stylesheet
Rails (Asset Pipeline / Sprockets):
In application.css:
/*
*= require ohhighmark/ohhighmark
*/Or in application.scss:
@import 'ohhighmark/ohhighmark';Rails (Propshaft / Importmap):
Copy the stylesheet:
$ cp $(bundle show ohhighmark)/app/assets/stylesheets/ohhighmark/ohhighmark.css app/assets/stylesheets/Link in your layout:
<%= stylesheet_link_tag "ohhighmark" %>Middleman:
Copy the stylesheet:
$ cp $(bundle show ohhighmark)/app/assets/stylesheets/ohhighmark/ohhighmark.css source/stylesheets/Then import it in your main stylesheet.
Standalone / Other Frameworks:
Find the stylesheet in the gem:
$ bundle show ohhighmark
# Copy app/assets/stylesheets/ohhighmark/ohhighmark.css to your projectCustomizing Colors
Override CSS variables after including the OhHighMark stylesheet:
:root {
/* Text and background */
--ohm-text-color: #ffffff;
--ohm-background-color: #1a1a1a;
--ohm-linenos-color: #666666;
--ohm-linenos-bg-color: #1a1a1a;
/* Syntax colors */
--ohm-yellow: #ffff00; /* H1 headings */
--ohm-orange: #ff8000; /* H2 headings */
--ohm-purple: #ff00ff; /* H3 headings */
--ohm-cyan: #00ffff; /* H4-H6 headings */
--ohm-blue: #0080ff; /* Links */
--ohm-intense-blue: #0040ff; /* Link hover */
--ohm-green: #00ff00; /* Quotes, lists */
--ohm-gray: #808080; /* Horizontal rules */
--ohm-grayish: #999999; /* Table borders */
/* Table highlighting */
--ohm-table-bg: rgba(255, 248, 197, 0.2);
/* Font */
--ohm-monospace-font: "Courier New", monospace;
}Dark Theme Example:
:root {
--ohm-text-color: #e0e0e0;
--ohm-background-color: #0d1117;
--ohm-linenos-bg-color: #0d1117;
--ohm-linenos-color: #6e7681;
--ohm-blue: #4a9eff;
--ohm-green: #7cfc00;
--ohm-yellow: #ffd700;
--ohm-orange: #ff6b35;
}Light Theme Example:
:root {
--ohm-text-color: #333333;
--ohm-background-color: #ffffff;
--ohm-linenos-bg-color: #f6f8fa;
--ohm-linenos-color: #57606a;
--ohm-blue: #0969da;
--ohm-green: #1a7f37;
--ohm-yellow: #b8860b;
--ohm-orange: #d2691e;
}HTML Structure
OhHighMark generates semantic HTML with clean structure:
<div class="ohhighmark">
<table class="highlight">
<tbody>
<!-- Regular content row -->
<tr data-line-number="1">
<td class="blob-num">1</td>
<td class="blob-code"><span class="md-h1"># Heading</span></td>
</tr>
<!-- Row with text -->
<tr data-line-number="2">
<td class="blob-num">2</td>
<td class="blob-code">Some text with <span class="md-bold">**bold**</span></td>
</tr>
<!-- Table row (has table-line class) -->
<tr class="table-line" data-line-number="3">
<td class="blob-num">3</td>
<td class="blob-code"><span class="md-table-pipe">|</span> Col 1 <span class="md-table-pipe">|</span> Col 2 <span class="md-table-pipe">|</span></td>
</tr>
</tbody>
</table>
</div>Key Structure Points:
-
data-line-numberattribute on<tr>for easy row targeting -
.blob-numcell contains line number -
.blob-codecell contains formatted content -
.table-lineclass added to rows that are part of markdown tables - Markdown syntax wrapped in
<span>elements with.md-*classes
CSS Classes Reference
Container & Layout:
-
.ohhighmark- Main container div -
table.highlight- Table element containing all lines -
.blob-num- Line number cell (user-select: noneprevents copying) -
.blob-code- Code content cell (useswhite-space: pre) -
.table-line- Added to<tr>for markdown table rows
Markdown Syntax Classes:
-
.md-h1through.md-h6- Heading levels 1-6 -
.md-bold- Bold text (**text**) -
.md-italic- Italic text (_text_) -
.md-em- Bold-italic emphasis (***text***) -
.md-strikethrough- Strikethrough (~~text~~) -
.md-code- Inline code (`code`) -
.md-link- Standard links ([text](url)) -
.md-autolink- Auto-linked URLs (<http://url>) -
.md-li- List item markers -
.md-hr- Horizontal rules (---) -
.md-fence- Fenced code block delimiters -
.md-codeblock- Content within fenced code blocks -
.md-table-pipe- Table pipe characters (|) -
.md-table-dash- Table separator rows (---) -
.md-quote- Block quotes (> text)
Critical CSS Requirements
The .blob-code cell MUST have white-space: pre to preserve whitespace and prevent wrapping:
.ohhighmark td.blob-code {
white-space: pre; /* REQUIRED - preserves all whitespace */
font-family: ui-monospace, monospace;
line-height: 20px;
}Frontend JavaScript Integration
Target rows by line number:
// Select a specific line
const row = document.querySelector('[data-line-number="5"]');
// Highlight a line
row.style.backgroundColor = 'rgba(255, 255, 0, 0.2)';
// Get all table rows
const tableRows = document.querySelectorAll('tr[data-line-number]');Contributing
Bug reports and pull requests are welcome!
Development Setup
$ git clone https://github.com/viacoffee/ohhighmark.git
$ cd ohhighmark
$ bundle install
$ rspec # Run testsLicense
This gem is available as open source under the terms of the MIT License.