Demo: Inline Code Snippets in Hugo
This post demonstrates how to inline code snippets from external source files using Hugo shortcodes.
Overview
Instead of copying code into markdown files, we can maintain source code separately and pull specific regions into our posts. This keeps code DRY and ensures examples stay in sync with actual source files.
Example: A Simple Parser
Let’s look at a toy parser implementation. First, we define our token types:
#[derive(Debug, Clone, PartialEq)]
enum Token {
Number(f64),
Identifier(String),
Plus,
Minus,
Star,
Slash,
LeftParen,
RightParen,
}The tokenizer needs to handle numbers specially, since they can span multiple characters:
fn read_number(&mut self) -> Token {
let mut num_str = String::new();
while self.position < self.input.len() {
let ch = self.input[self.position];
if ch.is_numeric() || ch == '.' {
num_str.push(ch);
self.position += 1;
} else {
break;
}
}
Token::Number(num_str.parse().unwrap())
}And here’s the main tokenization loop that ties it all together:
fn tokenize(&mut self) -> Vec<Token> {
let mut tokens = Vec::new();
while self.position < self.input.len() {
self.skip_whitespace();
if self.position >= self.input.len() {
break;
}
let ch = self.input[self.position];
let token = match ch {
'+' => { self.position += 1; Token::Plus }
'-' => { self.position += 1; Token::Minus }
'*' => { self.position += 1; Token::Star }
'/' => { self.position += 1; Token::Slash }
'(' => { self.position += 1; Token::LeftParen }
')' => { self.position += 1; Token::RightParen }
'0'..='9' => self.read_number(),
_ => panic!("Unexpected character: {}", ch),
};
tokens.push(token);
}
tokens
}How It Works
In the source file (static/examples/parser.rs), regions are marked with comments:
// SNIPPET_START: region_name
... code to extract ...
// SNIPPET_END: region_name
Then in markdown, use the shortcode:
{{< code-snippet file="static/examples/parser.rs" region="region_name" lang="rust" >}}
Benefits
- Single source of truth: Code lives in actual source files
- Type checking: Your examples can be compiled/tested
- Easy updates: Change the source file, and all posts update automatically
- Clean separation: Keep code and prose separate
The full source file is available at /examples/parser.rs.