From fca1a9aadb1ad2261ac8f1e8afc2def97c06db51 Mon Sep 17 00:00:00 2001 From: Grant Lemons Date: Tue, 31 Dec 2024 00:17:00 -0600 Subject: [PATCH 1/7] feat(#331): create literate haskell masker and parser --- Cargo.lock | 13 ++++++ Cargo.toml | 2 +- harper-cli/Cargo.toml | 1 + harper-cli/src/main.rs | 11 ++--- harper-literate-haskell/Cargo.toml | 11 +++++ harper-literate-haskell/src/lib.rs | 41 ++++++++++++++++++ harper-literate-haskell/src/masker.rs | 39 +++++++++++++++++ harper-literate-haskell/tests/run_tests.rs | 42 +++++++++++++++++++ .../tests/test_sources/bird_format.lhs | 9 ++++ .../tests/test_sources/latex_format.lhs | 12 ++++++ .../tests/test_sources/mixed_format.lhs | 20 +++++++++ harper-ls/Cargo.toml | 1 + harper-ls/src/backend.rs | 25 +++++++++++ 13 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 harper-literate-haskell/Cargo.toml create mode 100644 harper-literate-haskell/src/lib.rs create mode 100644 harper-literate-haskell/src/masker.rs create mode 100644 harper-literate-haskell/tests/run_tests.rs create mode 100644 harper-literate-haskell/tests/test_sources/bird_format.lhs create mode 100644 harper-literate-haskell/tests/test_sources/latex_format.lhs create mode 100644 harper-literate-haskell/tests/test_sources/mixed_format.lhs diff --git a/Cargo.lock b/Cargo.lock index 224e6ff6..5e790c5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -560,6 +560,7 @@ dependencies = [ "clap", "harper-comments", "harper-core", + "harper-literate-haskell", "serde_json", ] @@ -626,6 +627,17 @@ dependencies = [ "tree-sitter-html", ] +[[package]] +name = "harper-literate-haskell" +version = "0.13.0" +dependencies = [ + "harper-comments", + "harper-core", + "harper-tree-sitter", + "itertools 0.13.0", + "paste", +] + [[package]] name = "harper-ls" version = "0.13.0" @@ -637,6 +649,7 @@ dependencies = [ "harper-comments", "harper-core", "harper-html", + "harper-literate-haskell", "itertools 0.13.0", "once_cell", "open", diff --git a/Cargo.toml b/Cargo.toml index 9a2546b5..a25b424c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = [ "harper-cli", "harper-core", "harper-ls", "harper-comments", "harper-wasm", "harper-tree-sitter", "harper-html"] +members = [ "harper-cli", "harper-core", "harper-ls", "harper-comments", "harper-wasm", "harper-tree-sitter", "harper-html", "harper-literate-haskell"] resolver = "2" [profile.release] diff --git a/harper-cli/Cargo.toml b/harper-cli/Cargo.toml index 7c69db72..34bfde3d 100644 --- a/harper-cli/Cargo.toml +++ b/harper-cli/Cargo.toml @@ -11,5 +11,6 @@ anyhow = "1.0.95" ariadne = "0.4.1" clap = { version = "4.5.23", features = ["derive"] } harper-core = { path = "../harper-core", version = "0.13.0" } +harper-literate-haskell = { path = "../harper-literate-haskell", version = "0.13.0" } harper-comments = { path = "../harper-comments", version = "0.13.0" } serde_json = "1.0.133" diff --git a/harper-cli/src/main.rs b/harper-cli/src/main.rs index ef57427b..48ba99a8 100644 --- a/harper-cli/src/main.rs +++ b/harper-cli/src/main.rs @@ -9,6 +9,7 @@ use harper_comments::CommentParser; use harper_core::linting::{LintGroup, LintGroupConfig, Linter}; use harper_core::parsers::Markdown; use harper_core::{remove_overlaps, Dictionary, Document, FstDictionary}; +use harper_literate_haskell::LiterateHaskellParser; #[derive(Debug, Parser)] enum Args { @@ -143,14 +144,14 @@ fn load_file(file: &Path) -> anyhow::Result<(Document, String)> { let source = std::fs::read_to_string(file)?; let mut parser: Box = - if let Some("md") = file.extension().map(|v| v.to_str().unwrap()) { - Box::new(Markdown) - } else { - Box::new( + match file.extension().map(|v| v.to_str().unwrap()) { + Some("md") => Box::new(Markdown), + Some("lhs") => Box::new(LiterateHaskellParser), + _ => Box::new( CommentParser::new_from_filename(file) .map(Box::new) .ok_or(format_err!("Could not detect language ID."))?, - ) + ), }; Ok((Document::new_curated(&source, &mut parser), source)) diff --git a/harper-literate-haskell/Cargo.toml b/harper-literate-haskell/Cargo.toml new file mode 100644 index 00000000..bdee1388 --- /dev/null +++ b/harper-literate-haskell/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "harper-literate-haskell" +version = "0.13.0" +edition = "2021" + +[dependencies] +harper-core = { path = "../harper-core", version = "0.13.0" } +harper-tree-sitter = { path = "../harper-tree-sitter", version = "0.13.0" } +harper-comments = { path = "../harper-comments", version = "0.13.0" } +itertools = "0.13.0" +paste = "1.0.14" diff --git a/harper-literate-haskell/src/lib.rs b/harper-literate-haskell/src/lib.rs new file mode 100644 index 00000000..4317c97f --- /dev/null +++ b/harper-literate-haskell/src/lib.rs @@ -0,0 +1,41 @@ +use harper_comments::CommentParser; +use harper_core::{ + parsers::{Markdown, Mask, Parser}, + FullDictionary, Masker, Token, +}; + +mod masker; +use itertools::Itertools; +use masker::LiterateHaskellMasker; + +pub struct LiterateHaskellParser; + +impl LiterateHaskellParser { + pub fn create_ident_dict(&self, source: &[char]) -> Option { + let parser = CommentParser::new_from_language_id("haskell").unwrap(); + let mask = LiterateHaskellMasker { + text: false, + code: true, + } + .create_mask(source); + + let code = mask + .iter_allowed(source) + .flat_map(|(_, src)| src.to_owned()) + .collect_vec(); + parser.create_ident_dict(&code) + } +} + +impl Parser for LiterateHaskellParser { + fn parse(&mut self, source: &[char]) -> Vec { + Mask::new( + LiterateHaskellMasker { + text: true, + code: false, + }, + Markdown, + ) + .parse(source) + } +} diff --git a/harper-literate-haskell/src/masker.rs b/harper-literate-haskell/src/masker.rs new file mode 100644 index 00000000..2627576a --- /dev/null +++ b/harper-literate-haskell/src/masker.rs @@ -0,0 +1,39 @@ +use harper_core::{CharStringExt, Mask, Masker, Span}; + +pub struct LiterateHaskellMasker { + pub text: bool, + pub code: bool, +} + +impl Masker for LiterateHaskellMasker { + fn create_mask(&mut self, source: &[char]) -> harper_core::Mask { + let mut mask = Mask::new_blank(); + + let mut location = 0; + let mut in_code_env = false; + let mut last_line_blank = false; + + for line in source.split(|c| *c == '\n') { + let string_form = line.to_string(); + let trimmed = string_form.trim(); + let line_is_bird = line.first().map_or(false, |c| *c == '>'); + + // Code fencing + let code_start = trimmed == r"\begin{code}" || (last_line_blank && line_is_bird); + let code_end = trimmed == r"\end{code}" || trimmed.is_empty(); + if (!in_code_env && code_start) || (in_code_env && code_end) { + in_code_env = !in_code_env; + } + + let end_loc = location + line.len(); + if (!in_code_env && self.text) || (in_code_env && self.code) { + mask.push_allowed(Span::new(location, end_loc)); + } + + location = end_loc + 1; // +1 for the newline split on + last_line_blank = trimmed.is_empty(); + } + + mask + } +} diff --git a/harper-literate-haskell/tests/run_tests.rs b/harper-literate-haskell/tests/run_tests.rs new file mode 100644 index 00000000..0bbe25c5 --- /dev/null +++ b/harper-literate-haskell/tests/run_tests.rs @@ -0,0 +1,42 @@ +use harper_core::linting::{LintGroup, LintGroupConfig, Linter}; +use harper_core::{Document, FstDictionary}; +use harper_literate_haskell::LiterateHaskellParser; + +/// Creates a unit test checking that the linting of a Markdown document (in +/// `tests_sources`) produces the expected number of lints. +macro_rules! create_test { + ($filename:ident.lhs, $correct_expected:expr) => { + paste::paste! { + #[test] + fn [](){ + let source = include_str!( + concat!( + "./test_sources/", + concat!(stringify!($filename), ".lhs") + ) + ); + + let dict = FstDictionary::curated(); + let document = Document::new_curated(&source, &mut LiterateHaskellParser); + + let mut linter = LintGroup::new( + LintGroupConfig::default(), + dict + ); + let lints = linter.lint(&document); + + dbg!(&lints); + assert_eq!(lints.len(), $correct_expected); + + // Make sure that all generated tokens span real characters + for token in document.tokens(){ + assert!(token.span.try_get_content(document.get_source()).is_some()); + } + } + } + }; +} + +create_test!(bird_format.lhs, 0); +create_test!(latex_format.lhs, 0); +create_test!(mixed_format.lhs, 0); diff --git a/harper-literate-haskell/tests/test_sources/bird_format.lhs b/harper-literate-haskell/tests/test_sources/bird_format.lhs new file mode 100644 index 00000000..64153531 --- /dev/null +++ b/harper-literate-haskell/tests/test_sources/bird_format.lhs @@ -0,0 +1,9 @@ +Sourced from https://wiki.haskell.org/Literate_programming. + +In Bird-style you have to leave a blank before the code. + +> fact :: Integer -> Integer +> fact 0 = 1 +> fact n = n * fact (n-1) + +And you have to leave a blank line after the code as well. diff --git a/harper-literate-haskell/tests/test_sources/latex_format.lhs b/harper-literate-haskell/tests/test_sources/latex_format.lhs new file mode 100644 index 00000000..44fd441d --- /dev/null +++ b/harper-literate-haskell/tests/test_sources/latex_format.lhs @@ -0,0 +1,12 @@ +Sourced from https://wiki.haskell.org/Literate_programming. + +And the definition of the following function +would totally screw up my program, so I'm not +definining it: + +\begin{code} +main :: IO () +main = print "just an example" +\end{code} + +See? diff --git a/harper-literate-haskell/tests/test_sources/mixed_format.lhs b/harper-literate-haskell/tests/test_sources/mixed_format.lhs new file mode 100644 index 00000000..b89ef126 --- /dev/null +++ b/harper-literate-haskell/tests/test_sources/mixed_format.lhs @@ -0,0 +1,20 @@ +Sourced from https://wiki.haskell.org/Literate_programming. + +In Bird-style you have to leave a blank before the code. + +> fact :: Integer -> Integer +> fact 0 = 1 +> fact n = n * fact (n-1) + +And you have to leave a blank line after the code as well. + +And the definition of the following function +would totally screw up my program, so I'm not +definining it: + +\begin{code} +main :: IO () +main = print "just an example" +\end{code} + +See? diff --git a/harper-ls/Cargo.toml b/harper-ls/Cargo.toml index 998ac77d..3dc16c65 100644 --- a/harper-ls/Cargo.toml +++ b/harper-ls/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/automattic/harper" [dependencies] harper-core = { path = "../harper-core", version = "0.13.0", features = ["concurrent"] } harper-comments = { path = "../harper-comments", version = "0.13.0" } +harper-literate-haskell = { path = "../harper-literate-haskell", version = "0.13.0" } harper-html = { path = "../harper-html", version = "0.13.0" } tower-lsp = "0.20.0" tokio = { version = "1.42.0", features = ["fs", "rt", "rt-multi-thread", "macros", "io-std", "io-util", "net"] } diff --git a/harper-ls/src/backend.rs b/harper-ls/src/backend.rs index 73ceedeb..7c4b5b8e 100644 --- a/harper-ls/src/backend.rs +++ b/harper-ls/src/backend.rs @@ -11,6 +11,7 @@ use harper_core::{ WordMetadata, }; use harper_html::HtmlParser; +use harper_literate_haskell::LiterateHaskellParser; use serde_json::Value; use tokio::sync::{Mutex, RwLock}; use tower_lsp::jsonrpc::Result; @@ -204,6 +205,30 @@ impl Backend { } else { Some(Box::new(ts_parser)) } + } else if language_id == "lhaskell" { + let source: Vec = text.chars().collect(); + let source = Arc::new(source); + + let parser = LiterateHaskellParser; + if let Some(new_dict) = parser.create_ident_dict(source.as_slice()) { + let new_dict = Arc::new(new_dict); + + if doc_state.ident_dict != new_dict { + doc_state.ident_dict = new_dict.clone(); + let mut merged = self.generate_file_dictionary(url).await?; + merged.add_dictionary(new_dict); + let merged = Arc::new(merged); + + doc_state.linter = LintGroup::new(config_lock.lint_config, merged.clone()); + doc_state.dict = merged.clone(); + } + Some(Box::new(CollapseIdentifiers::new( + Box::new(parser), + Box::new(doc_state.dict.clone()), + ))) + } else { + Some(Box::new(parser)) + } } else if language_id == "markdown" { Some(Box::new(Markdown)) } else if language_id == "git-commit" { From 1a8ed8df3894b7564ffde4ac7158b07d23d77e4f Mon Sep 17 00:00:00 2001 From: Grant Lemons Date: Tue, 31 Dec 2024 16:33:25 -0600 Subject: [PATCH 2/7] tests(#331): change tests to have spelling issues --- harper-literate-haskell/tests/run_tests.rs | 6 +++--- harper-literate-haskell/tests/test_sources/bird_format.lhs | 4 ++-- harper-literate-haskell/tests/test_sources/latex_format.lhs | 2 +- harper-literate-haskell/tests/test_sources/mixed_format.lhs | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/harper-literate-haskell/tests/run_tests.rs b/harper-literate-haskell/tests/run_tests.rs index 0bbe25c5..f367f66b 100644 --- a/harper-literate-haskell/tests/run_tests.rs +++ b/harper-literate-haskell/tests/run_tests.rs @@ -37,6 +37,6 @@ macro_rules! create_test { }; } -create_test!(bird_format.lhs, 0); -create_test!(latex_format.lhs, 0); -create_test!(mixed_format.lhs, 0); +create_test!(bird_format.lhs, 2); +create_test!(latex_format.lhs, 2); +create_test!(mixed_format.lhs, 4); diff --git a/harper-literate-haskell/tests/test_sources/bird_format.lhs b/harper-literate-haskell/tests/test_sources/bird_format.lhs index 64153531..4a9590c0 100644 --- a/harper-literate-haskell/tests/test_sources/bird_format.lhs +++ b/harper-literate-haskell/tests/test_sources/bird_format.lhs @@ -1,9 +1,9 @@ Sourced from https://wiki.haskell.org/Literate_programming. -In Bird-style you have to leave a blank before the code. +In Bird-style you have to leave a blnk before the code. > fact :: Integer -> Integer > fact 0 = 1 > fact n = n * fact (n-1) -And you have to leave a blank line after the code as well. +And you have to leave a blnk line after the code as well. diff --git a/harper-literate-haskell/tests/test_sources/latex_format.lhs b/harper-literate-haskell/tests/test_sources/latex_format.lhs index 44fd441d..17e703fa 100644 --- a/harper-literate-haskell/tests/test_sources/latex_format.lhs +++ b/harper-literate-haskell/tests/test_sources/latex_format.lhs @@ -9,4 +9,4 @@ main :: IO () main = print "just an example" \end{code} -See? +Seee? diff --git a/harper-literate-haskell/tests/test_sources/mixed_format.lhs b/harper-literate-haskell/tests/test_sources/mixed_format.lhs index b89ef126..051fa9ba 100644 --- a/harper-literate-haskell/tests/test_sources/mixed_format.lhs +++ b/harper-literate-haskell/tests/test_sources/mixed_format.lhs @@ -1,12 +1,12 @@ Sourced from https://wiki.haskell.org/Literate_programming. -In Bird-style you have to leave a blank before the code. +In Bird-style you have to leave a blnk before the code. > fact :: Integer -> Integer > fact 0 = 1 > fact n = n * fact (n-1) -And you have to leave a blank line after the code as well. +And you have to leave a blnk line after the code as well. And the definition of the following function would totally screw up my program, so I'm not @@ -17,4 +17,4 @@ main :: IO () main = print "just an example" \end{code} -See? +Seee? From f8e6e772674dbc28e9618be9940eb0a6b5a2cd19 Mon Sep 17 00:00:00 2001 From: Grant Lemons Date: Tue, 31 Dec 2024 16:33:40 -0600 Subject: [PATCH 3/7] tests(#331): create literate haskell masker unit tests --- harper-literate-haskell/src/lib.rs | 15 +--- harper-literate-haskell/src/masker.rs | 112 +++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 16 deletions(-) diff --git a/harper-literate-haskell/src/lib.rs b/harper-literate-haskell/src/lib.rs index 4317c97f..c18efd9d 100644 --- a/harper-literate-haskell/src/lib.rs +++ b/harper-literate-haskell/src/lib.rs @@ -13,11 +13,7 @@ pub struct LiterateHaskellParser; impl LiterateHaskellParser { pub fn create_ident_dict(&self, source: &[char]) -> Option { let parser = CommentParser::new_from_language_id("haskell").unwrap(); - let mask = LiterateHaskellMasker { - text: false, - code: true, - } - .create_mask(source); + let mask = LiterateHaskellMasker::code_only().create_mask(source); let code = mask .iter_allowed(source) @@ -29,13 +25,6 @@ impl LiterateHaskellParser { impl Parser for LiterateHaskellParser { fn parse(&mut self, source: &[char]) -> Vec { - Mask::new( - LiterateHaskellMasker { - text: true, - code: false, - }, - Markdown, - ) - .parse(source) + Mask::new(LiterateHaskellMasker::text_only(), Markdown).parse(source) } } diff --git a/harper-literate-haskell/src/masker.rs b/harper-literate-haskell/src/masker.rs index 2627576a..3038cb6f 100644 --- a/harper-literate-haskell/src/masker.rs +++ b/harper-literate-haskell/src/masker.rs @@ -1,8 +1,24 @@ use harper_core::{CharStringExt, Mask, Masker, Span}; pub struct LiterateHaskellMasker { - pub text: bool, - pub code: bool, + text: bool, + code: bool, +} + +impl LiterateHaskellMasker { + pub fn text_only() -> Self { + Self { + text: true, + code: false, + } + } + + pub fn code_only() -> Self { + Self { + text: false, + code: true, + } + } } impl Masker for LiterateHaskellMasker { @@ -19,21 +35,111 @@ impl Masker for LiterateHaskellMasker { let line_is_bird = line.first().map_or(false, |c| *c == '>'); // Code fencing + let latex_style = matches!(trimmed, r"\begin{code}" | r"\end{code}"); let code_start = trimmed == r"\begin{code}" || (last_line_blank && line_is_bird); let code_end = trimmed == r"\end{code}" || trimmed.is_empty(); + + // Toggle on fence if (!in_code_env && code_start) || (in_code_env && code_end) { in_code_env = !in_code_env; + + // Exclude latex-style fence + if latex_style { + location += line.len() + 1; // +1 for the newline split on + last_line_blank = trimmed.is_empty(); + continue; + } + + // Exclude newline after code for bird style + if trimmed.is_empty() { + location += line.len() + 1; // +1 for the newline split on + last_line_blank = true; + continue; + } } let end_loc = location + line.len(); if (!in_code_env && self.text) || (in_code_env && self.code) { - mask.push_allowed(Span::new(location, end_loc)); + let start_loc = if line_is_bird { location + 2 } else { location }; + mask.push_allowed(Span::new(start_loc, end_loc)); } location = end_loc + 1; // +1 for the newline split on last_line_blank = trimmed.is_empty(); } + mask.merge_whitespace_sep(source); mask } } + +#[cfg(test)] +mod tests { + use harper_core::{Masker, Span}; + use itertools::Itertools; + + use super::LiterateHaskellMasker; + + #[test] + fn bird_format() { + let source = r"Text here + +> fact :: Integer -> Integer +> fact 0 = 1 +> fact n = n * fact (n-1) + +Text here +" + .chars() + .collect_vec(); + + let text_mask = LiterateHaskellMasker::text_only().create_mask(&source); + assert_eq!( + text_mask + .iter_allowed(&source) + .map(|(s, _)| s) + .collect_vec(), + vec![Span::new(0, 10), Span::new(80, 90)], + ); + + let code_mask = LiterateHaskellMasker::code_only().create_mask(&source); + assert_eq!( + code_mask + .iter_allowed(&source) + .map(|(s, _)| s) + .collect_vec(), + vec![Span::new(13, 39), Span::new(42, 52), Span::new(55, 78)], + ); + } + + #[test] + fn latex_format() { + let source = r#"Text here +\begin{code} +main :: IO () +main = print "just an example" +\end{code} +Text here +"# + .chars() + .collect_vec(); + + let text_mask = LiterateHaskellMasker::text_only().create_mask(&source); + assert_eq!( + text_mask + .iter_allowed(&source) + .map(|(s, _)| s) + .collect_vec(), + vec![Span::new(0, 9), Span::new(79, 89)], + ); + + let code_mask = LiterateHaskellMasker::code_only().create_mask(&source); + assert_eq!( + code_mask + .iter_allowed(&source) + .map(|(s, _)| s) + .collect_vec(), + vec![Span::new(23, 67)], + ); + } +} From 50a7c14c481e98773f12de9c5524a189cf929674 Mon Sep 17 00:00:00 2001 From: Grant Lemons Date: Tue, 31 Dec 2024 16:44:47 -0600 Subject: [PATCH 4/7] refactor(#331): simplify ident dict code --- harper-ls/src/backend.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/harper-ls/src/backend.rs b/harper-ls/src/backend.rs index 7c4b5b8e..fc1f1158 100644 --- a/harper-ls/src/backend.rs +++ b/harper-ls/src/backend.rs @@ -12,6 +12,7 @@ use harper_core::{ }; use harper_html::HtmlParser; use harper_literate_haskell::LiterateHaskellParser; +use itertools::Itertools; use serde_json::Value; use tokio::sync::{Mutex, RwLock}; use tower_lsp::jsonrpc::Result; @@ -183,14 +184,14 @@ impl Backend { let parser: Option> = if let Some(ts_parser) = CommentParser::new_from_language_id(language_id) { - let source: Vec = text.chars().collect(); - let source = Arc::new(source); + let source = text.chars().collect_vec(); - if let Some(new_dict) = ts_parser.create_ident_dict(source.as_slice()) { + if let Some(new_dict) = ts_parser.create_ident_dict(&source) { let new_dict = Arc::new(new_dict); if doc_state.ident_dict != new_dict { doc_state.ident_dict = new_dict.clone(); + let mut merged = self.generate_file_dictionary(url).await?; merged.add_dictionary(new_dict); let merged = Arc::new(merged); @@ -206,15 +207,15 @@ impl Backend { Some(Box::new(ts_parser)) } } else if language_id == "lhaskell" { - let source: Vec = text.chars().collect(); - let source = Arc::new(source); - + let source = text.chars().collect_vec(); let parser = LiterateHaskellParser; - if let Some(new_dict) = parser.create_ident_dict(source.as_slice()) { + + if let Some(new_dict) = parser.create_ident_dict(&source) { let new_dict = Arc::new(new_dict); if doc_state.ident_dict != new_dict { doc_state.ident_dict = new_dict.clone(); + let mut merged = self.generate_file_dictionary(url).await?; merged.add_dictionary(new_dict); let merged = Arc::new(merged); From 15d00d5ebe71aff7c6a1c6c88eb08910a0c6a8ac Mon Sep 17 00:00:00 2001 From: Grant Lemons Date: Mon, 6 Jan 2025 13:08:12 -0700 Subject: [PATCH 5/7] fix: add crate info to Cargo.toml --- harper-literate-haskell/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/harper-literate-haskell/Cargo.toml b/harper-literate-haskell/Cargo.toml index dd5450df..a368c11b 100644 --- a/harper-literate-haskell/Cargo.toml +++ b/harper-literate-haskell/Cargo.toml @@ -2,6 +2,9 @@ name = "harper-literate-haskell" version = "0.14.0" edition = "2021" +description = "The language checker for developers." +license = "Apache-2.0" +repository = "https://github.com/automattic/harper" [dependencies] harper-core = { path = "../harper-core", version = "0.14.0" } From e3d7acf234e9089653b80358b0925243bb0fb8d2 Mon Sep 17 00:00:00 2001 From: Grant Lemons Date: Tue, 7 Jan 2025 10:52:08 -0700 Subject: [PATCH 6/7] feat: add doc comments to literate haskell structs --- harper-literate-haskell/src/lib.rs | 1 + harper-literate-haskell/src/masker.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/harper-literate-haskell/src/lib.rs b/harper-literate-haskell/src/lib.rs index c18efd9d..f56515a7 100644 --- a/harper-literate-haskell/src/lib.rs +++ b/harper-literate-haskell/src/lib.rs @@ -8,6 +8,7 @@ mod masker; use itertools::Itertools; use masker::LiterateHaskellMasker; +/// Parses a Literate Haskell document by masking out the code and considering text as Markdown. pub struct LiterateHaskellParser; impl LiterateHaskellParser { diff --git a/harper-literate-haskell/src/masker.rs b/harper-literate-haskell/src/masker.rs index 3038cb6f..daa20ff7 100644 --- a/harper-literate-haskell/src/masker.rs +++ b/harper-literate-haskell/src/masker.rs @@ -1,5 +1,8 @@ use harper_core::{CharStringExt, Mask, Masker, Span}; +/// Masker for selecting portions of Literate Haskell documents. +/// +/// Based on the specifications outlined at https://wiki.haskell.org/Literate_programming. pub struct LiterateHaskellMasker { text: bool, code: bool, From cd4aca55c09fa8b561eaf415245e0ae1d29c430c Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Fri, 10 Jan 2025 12:40:26 -0700 Subject: [PATCH 7/7] fix: hidden merge fallout --- Cargo.lock | 11 ++++++++++- harper-literate-haskell/Cargo.toml | 6 +++--- harper-literate-haskell/src/masker.rs | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7a12ba1..eae3ce58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -630,7 +630,7 @@ dependencies = [ [[package]] name = "harper-literate-haskell" -version = "0.14.0" +version = "0.15.0" dependencies = [ "harper-comments", "harper-core", @@ -918,6 +918,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" diff --git a/harper-literate-haskell/Cargo.toml b/harper-literate-haskell/Cargo.toml index 1637a7f3..d5b97e11 100644 --- a/harper-literate-haskell/Cargo.toml +++ b/harper-literate-haskell/Cargo.toml @@ -7,8 +7,8 @@ license = "Apache-2.0" repository = "https://github.com/automattic/harper" [dependencies] -harper-core = { path = "../harper-core", version = "0.14.0" } -harper-tree-sitter = { path = "../harper-tree-sitter", version = "0.14.0" } -harper-comments = { path = "../harper-comments", version = "0.14.0" } +harper-core = { path = "../harper-core", version = "0.15.0" } +harper-tree-sitter = { path = "../harper-tree-sitter", version = "0.15.0" } +harper-comments = { path = "../harper-comments", version = "0.15.0" } itertools = "0.13.0" paste = "1.0.14" diff --git a/harper-literate-haskell/src/masker.rs b/harper-literate-haskell/src/masker.rs index daa20ff7..bad9556c 100644 --- a/harper-literate-haskell/src/masker.rs +++ b/harper-literate-haskell/src/masker.rs @@ -35,7 +35,7 @@ impl Masker for LiterateHaskellMasker { for line in source.split(|c| *c == '\n') { let string_form = line.to_string(); let trimmed = string_form.trim(); - let line_is_bird = line.first().map_or(false, |c| *c == '>'); + let line_is_bird = line.first().is_some_and(|c| *c == '>'); // Code fencing let latex_style = matches!(trimmed, r"\begin{code}" | r"\end{code}");