|
1 | | -use once_cell::sync::Lazy; |
2 | | -use syntect::{ |
3 | | - easy::HighlightLines, |
4 | | - highlighting::{Style, Theme, ThemeSet}, |
5 | | - html::{append_highlighted_html_for_styled_line, IncludeBackground}, |
6 | | - parsing::SyntaxSet, |
7 | | - util::LinesWithEndings, |
8 | | -}; |
| 1 | +use gloo_worker::{oneshot::OneshotBridge, Spawnable}; |
| 2 | +use std::cell::RefCell; |
| 3 | + |
| 4 | +use worker::{HighlightRequest, HighlightWorker}; |
9 | 5 |
|
10 | 6 | pub struct HighlightService; |
11 | 7 |
|
12 | | -static SYNTAX_SET: Lazy<SyntaxSet> = Lazy::new(|| SyntaxSet::load_defaults_newlines()); |
13 | | -static THEME: Lazy<Theme> = Lazy::new(|| { |
14 | | - ThemeSet::load_defaults() |
15 | | - .themes |
16 | | - .get("base16-ocean.dark") |
17 | | - .cloned() |
18 | | - .unwrap_or_else(|| ThemeSet::load_defaults().themes["base16-eighties.dark"].clone()) |
19 | | -}); |
| 8 | +const WORKER_ENTRYPOINT: &str = "/highlight_worker.js"; |
| 9 | + |
| 10 | +thread_local! { |
| 11 | + static HIGHLIGHT_WORKER: RefCell<Option<OneshotBridge<HighlightWorker>>> = RefCell::new(None); |
| 12 | +} |
20 | 13 |
|
21 | 14 | impl HighlightService { |
22 | | - pub fn highlight_html(code: &str, language: Option<&str>) -> String { |
23 | | - Self::highlight_lines_html(code, language).join("\n") |
| 15 | + pub async fn highlight_html(code: &str, language: Option<&str>) -> String { |
| 16 | + Self::highlight_lines_html(code, language).await.join("\n") |
| 17 | + } |
| 18 | + |
| 19 | + pub async fn highlight_lines_html(code: &str, language: Option<&str>) -> Vec<String> { |
| 20 | + let request = HighlightRequest { |
| 21 | + code: code.to_owned(), |
| 22 | + language: language.map(str::to_owned), |
| 23 | + }; |
| 24 | + |
| 25 | + run_worker(request).await |
24 | 26 | } |
| 27 | +} |
25 | 28 |
|
26 | | - pub fn highlight_lines_html(code: &str, language: Option<&str>) -> Vec<String> { |
27 | | - let syntax = language |
28 | | - .and_then(|lang| SYNTAX_SET.find_syntax_by_token(lang)) |
29 | | - .unwrap_or_else(|| SYNTAX_SET.find_syntax_plain_text()); |
30 | | - |
31 | | - let mut highlighter = HighlightLines::new(syntax, &THEME); |
32 | | - let mut output = Vec::new(); |
33 | | - |
34 | | - for line in LinesWithEndings::from(code) { |
35 | | - let mut highlighted_line = String::new(); |
36 | | - if let Ok(ranges) = highlighter.highlight_line(line, &SYNTAX_SET) { |
37 | | - let _ = append_highlighted_html_for_styled_line( |
38 | | - &ranges, |
39 | | - IncludeBackground::No, |
40 | | - &mut highlighted_line, |
41 | | - ); |
42 | | - } else { |
43 | | - let _ = append_highlighted_html_for_styled_line( |
44 | | - &[(Style::default(), line)], |
45 | | - IncludeBackground::No, |
46 | | - &mut highlighted_line, |
47 | | - ); |
48 | | - } |
49 | | - |
50 | | - let highlighted_line = highlighted_line |
51 | | - .strip_suffix('\n') |
52 | | - .unwrap_or(&highlighted_line) |
53 | | - .to_owned(); |
54 | | - output.push(highlighted_line); |
| 29 | +async fn run_worker(request: HighlightRequest) -> Vec<String> { |
| 30 | + let mut bridge = HIGHLIGHT_WORKER.with(|cell| { |
| 31 | + let mut worker = cell.borrow_mut(); |
| 32 | + if worker.is_none() { |
| 33 | + let base = HighlightWorker::spawner().spawn(WORKER_ENTRYPOINT); |
| 34 | + *worker = Some(base); |
55 | 35 | } |
56 | 36 |
|
57 | | - output |
| 37 | + worker.as_ref().expect("worker initialized above").fork() |
| 38 | + }); |
| 39 | + |
| 40 | + bridge.run(request).await |
| 41 | +} |
| 42 | + |
| 43 | +pub mod worker { |
| 44 | + use gloo_worker::{oneshot::oneshot, Registrable}; |
| 45 | + use serde::{Deserialize, Serialize}; |
| 46 | + |
| 47 | + #[derive(Debug, Clone, Serialize, Deserialize)] |
| 48 | + pub struct HighlightRequest { |
| 49 | + pub code: String, |
| 50 | + pub language: Option<String>, |
| 51 | + } |
| 52 | + |
| 53 | + #[oneshot(HighlightWorker)] |
| 54 | + pub(crate) async fn highlight_worker(request: HighlightRequest) -> Vec<String> { |
| 55 | + crate::highlight_engine::HighlightEngine::highlight_lines( |
| 56 | + &request.code, |
| 57 | + request.language.as_deref(), |
| 58 | + ) |
| 59 | + } |
| 60 | + |
| 61 | + pub fn register() { |
| 62 | + HighlightWorker::registrar().register(); |
58 | 63 | } |
59 | 64 | } |
0 commit comments