Skip to content

Commit

Permalink
Merge pull request #6392 from michaelkpfeifer/support-embedding-parts…
Browse files Browse the repository at this point in the history
…-of-files-with-static-site-gen-platform

Support embedding parts of files with the static site gen platform
  • Loading branch information
Anton-4 authored Jan 31, 2024
2 parents 82ddfbb + 0d26203 commit 98a9f52
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 46 deletions.
9 changes: 9 additions & 0 deletions examples/static-site-gen/input/subFolder/apple.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,21 @@ Herculei undae calcata inmeriti quercus ignes parabant iam.

### Example Code Blocks

#### Something That Cannot Be Found

```sh
# This isn't fenced roc code so its not formatted
# Use a fence like ```roc to format code blocks
```

#### A Complete File

```roc
file:codeExample.roc
```

#### A Snippet Of Some File

```roc
file:codeExample.roc:snippet:view
```
4 changes: 4 additions & 0 deletions examples/static-site-gen/input/subFolder/codeExample.roc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ transformFileContent = \currentUrl, htmlContent ->
|> Result.map Html.render
|> Result.withDefault ""

### start snippet view
view : NavLink, Str -> Html.Node
view = \currentNavLink, htmlContent ->
html [lang "en"] [
Expand All @@ -37,6 +38,7 @@ view = \currentNavLink, htmlContent ->
Html.title [] [text currentNavLink.title],
link [rel "stylesheet", href "style.css"] [],
],
### start snippet body
body [] [
div [class "main"] [
div [class "navbar"] [
Expand All @@ -49,7 +51,9 @@ view = \currentNavLink, htmlContent ->
],
],
],
### end snippet body
]
### end snippet view

viewNavbar : NavLink -> Html.Node
viewNavbar = \currentNavLink ->
Expand Down
121 changes: 75 additions & 46 deletions examples/static-site-gen/platform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ use libc;
use pulldown_cmark::{html, Options, Parser};
use roc_std::{RocBox, RocStr};
use std::env;
use std::ffi::CStr;
use std::fs;
use std::os::raw::c_char;
use std::path::{Path, PathBuf};

use syntect::easy::HighlightLines;
use syntect::highlighting::{Style, ThemeSet};
use syntect::highlighting::{ThemeSet};
use syntect::html::{ClassStyle, ClassedHTMLGenerator};
use syntect::parsing::SyntaxSet;
use syntect::util::LinesWithEndings;
Expand Down Expand Up @@ -244,17 +242,19 @@ fn process_file(input_dir: &Path, output_dir: &Path, input_file: &Path) -> Resul
pulldown_cmark::CodeBlockKind::Fenced(extention_str),
)) => {
if in_code_block {
match replace_code_with_static_file(&code_to_highlight, input_file) {
None => {}
// Check if the code block is actually just a relative
// path to a static file, if so replace the code with
// the contents of the file.
// ```
// file:myCodeFile.roc
// ```
Some(new_code_to_highlight) => {
code_to_highlight = new_code_to_highlight;
match &code_to_highlight.split(':').collect::<Vec<_>>()[..] {
["file", replacement_file_name, "snippet", snippet_name] => {
code_to_highlight = read_replacement_snippet(
replacement_file_name.trim(),
snippet_name.trim(),
input_file,
);
}
["file", replacement_file_name] => {
code_to_highlight =
read_replacement_file(replacement_file_name.trim(), input_file);
}
_ => {}
}

// Format the whole multi-line code block as HTML all at once
Expand Down Expand Up @@ -355,45 +355,74 @@ pub fn strip_windows_prefix(path_buf: PathBuf) -> std::path::PathBuf {
fn is_roc_code_block(cbk: &pulldown_cmark::CodeBlockKind) -> bool {
match cbk {
pulldown_cmark::CodeBlockKind::Indented => false,
pulldown_cmark::CodeBlockKind::Fenced(cow_str) => {
if cow_str.contains("roc") {
true
} else {
false
}
pulldown_cmark::CodeBlockKind::Fenced(cow_str) => cow_str.contains("roc")
}
}

fn read_replacement_file(replacement_file_name: &str, input_file: &Path) -> String {
if replacement_file_name.contains("../") {
panic!(
"ERROR File \"{}\" must be located within the input diretory.",
replacement_file_name
);
}

let input_dir = input_file.parent().unwrap();
let replacement_file_path = input_dir.join(replacement_file_name);

match fs::read(&replacement_file_path) {
Ok(content) => String::from_utf8(content).unwrap(),
Err(err) => {
panic!(
"ERROR File \"{}\" is unreadable:\n\t{}",
replacement_file_path.to_str().unwrap(),
err
);
}
}
}

fn replace_code_with_static_file(code: &str, input_file: &Path) -> Option<String> {
let input_dir = input_file.parent()?;
let trimmed_code = code.trim();

// Confirm the code block starts with a `file:` tag
match trimmed_code.strip_prefix("file:") {
None => None,
Some(path) => {
// File must be located in input folder or sub-directory
if path.contains("../") {
panic!("ERROR File must be located within the input diretory!");
}
fn remove_snippet_comments(input: &str) -> String {
let line_ending = if input.contains("\r\n") { "\r\n" } else { "\n" };

let file_path = input_dir.join(path);
input
.lines()
.filter(|line| {
!line.contains("### start snippet") && !line.contains("### end snippet")
})
.collect::<Vec<&str>>()
.join(line_ending)
}

// Check file exists before opening
match file_path.try_exists() {
Err(_) | Ok(false) => {
panic!(
"ERROR File does not exist: \"{}\"",
file_path.to_str().unwrap()
);
}
Ok(true) => {
let vec_u8 = fs::read(file_path).ok()?;
fn read_replacement_snippet(
replacement_file_name: &str,
snippet_name: &str,
input_file: &Path,
) -> String {
let start_marker = format!("### start snippet {}", snippet_name);
let end_marker = format!("### end snippet {}", snippet_name);

String::from_utf8(vec_u8).ok()
}
}
}
let replacement_file_content = read_replacement_file(replacement_file_name.trim(), input_file);

let start_position = replacement_file_content
.find(&start_marker)
.expect(format!("ERROR Failed to find snippet start \"{}\". ", &start_marker).as_str());

let end_position = replacement_file_content
.find(&end_marker)
.expect(format!("ERROR Failed to find snippet end \"{}\". ", &end_marker).as_str());

if start_position >= end_position {
let start_position_str = start_position.to_string();
let end_position_str = end_position.to_string();

panic!(
"ERROR Detected start position ({start_position_str}) of snippet \"{snippet_name}\" was greater than or equal to detected end position ({end_position_str})."
);
} else {
// We want to remove other snippet comments inside this one if they exist.
remove_snippet_comments(
&replacement_file_content[start_position + start_marker.len()..end_position]
)
}
}

0 comments on commit 98a9f52

Please sign in to comment.