Skip to content

Commit

Permalink
feat: added initial HTML support
Browse files Browse the repository at this point in the history
  • Loading branch information
elijah-potter committed Jul 15, 2024
1 parent 0f5c0f3 commit 37be1f5
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 59 deletions.
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [ "harper-cli", "harper-core", "harper-ls", "harper-comments", "harper-wasm", "harper-tree-sitter"]
members = [ "harper-cli", "harper-core", "harper-ls", "harper-comments", "harper-wasm", "harper-tree-sitter", "harper-html"]
resolver = "2"

[profile.release]
Expand Down
10 changes: 5 additions & 5 deletions harper-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ enum Args {
/// Whether to merely print out the number of errors encountered,
/// without further details.
#[arg(short, long)]
count: bool
count: bool,
},
/// Parse a provided document and print the detected symbols.
Parse {
/// The file you wish to parse.
file: PathBuf
}
file: PathBuf,
},
}

fn main() -> anyhow::Result<()> {
Expand All @@ -35,7 +35,7 @@ fn main() -> anyhow::Result<()> {

let mut linter = LintGroup::new(
LintGroupConfig::default(),
FullDictionary::create_from_curated()
FullDictionary::create_from_curated(),
);
let mut lints = linter.lint(&doc);

Expand Down Expand Up @@ -64,7 +64,7 @@ fn main() -> anyhow::Result<()> {
report_builder = report_builder.with_label(
Label::new((&filename, lint.span.into()))
.with_message(lint.message)
.with_color(primary_color)
.with_color(primary_color),
);
}

Expand Down
2 changes: 1 addition & 1 deletion harper-comments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

This crate holds a number of functions, but it is primarily a wrapper around `tree-sitter` that allows Harper to locate the comments of a wide variety of programming languages.
It also has purpose-built parsers for the structured comments of a number of languages, including Go.
These additional parsers are avaiable through the `TreeSitterParser` and are enabled automatically through there.
These additional parsers are available through the `CommentParser` and are enabled automatically through there.
14 changes: 14 additions & 0 deletions harper-html/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "harper-html"
version = "0.8.8"
edition = "2021"
description = "The language checker for developers."
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/elijah-potter/harper"

[dependencies]
harper-core = { path = "../harper-core", version = "0.8.0" }
harper-tree-sitter = { path = "../harper-tree-sitter", version = "0.8.0" }
tree-sitter-html = "0.19.0"
tree-sitter = "0.20.10"
29 changes: 29 additions & 0 deletions harper-html/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use harper_core::parsers::{self, Parser, PlainEnglish};
use harper_core::Token;
use harper_tree_sitter::TreeSitterMasker;
use tree_sitter::Node;

pub struct HtmlParser {
inner: parsers::Mask<TreeSitterMasker, PlainEnglish>
}

impl HtmlParser {
pub fn new() -> Self {
Self {
inner: parsers::Mask::new(
TreeSitterMasker::new(tree_sitter_html::language(), Self::node_condition),
PlainEnglish
)
}
}

fn node_condition(n: &Node) -> bool {
n.kind() == "text"
}
}

impl Parser for HtmlParser {
fn parse(&mut self, source: &[char]) -> Vec<Token> {
self.inner.parse(source)
}
}
1 change: 1 addition & 0 deletions harper-ls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ repository = "https://github.com/elijah-potter/harper"
[dependencies]
harper-core = { path = "../harper-core", version = "0.8.0", features = ["concurrent"] }
harper-comments = { path = "../harper-comments", version = "0.8.0" }
harper-html = { path = "../harper-html", version = "0.8.0" }
tower-lsp = "0.20.0"
tokio = { version = "1.36.0", features = ["fs", "rt", "rt-multi-thread", "macros", "io-std", "io-util", "net"] }
clap = { version = "4.5.1", features = ["derive"] }
Expand Down
81 changes: 29 additions & 52 deletions harper-ls/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,21 @@ use std::sync::Arc;
use harper_comments::CommentParser;
use harper_core::parsers::{Markdown, PlainEnglish};
use harper_core::{
Dictionary,
Document,
FullDictionary,
LintGroup,
Linter,
MergedDictionary,
Token,
TokenKind
Dictionary, Document, FullDictionary, LintGroup, Linter, MergedDictionary, Token, TokenKind,
};
use harper_html::HtmlParser;
use serde_json::Value;
use tokio::sync::{Mutex, RwLock};
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::notification::PublishDiagnostics;
use tower_lsp::lsp_types::{
CodeActionOrCommand,
CodeActionParams,
CodeActionProviderCapability,
CodeActionResponse,
Command,
Diagnostic,
DidChangeConfigurationParams,
DidChangeTextDocumentParams,
DidCloseTextDocumentParams,
DidOpenTextDocumentParams,
DidSaveTextDocumentParams,
ExecuteCommandOptions,
ExecuteCommandParams,
InitializeParams,
InitializeResult,
InitializedParams,
MessageType,
PublishDiagnosticsParams,
Range,
ServerCapabilities,
TextDocumentSyncCapability,
TextDocumentSyncKind,
TextDocumentSyncOptions,
TextDocumentSyncSaveOptions,
Url
CodeActionOrCommand, CodeActionParams, CodeActionProviderCapability, CodeActionResponse,
Command, Diagnostic, DidChangeConfigurationParams, DidChangeTextDocumentParams,
DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams,
ExecuteCommandOptions, ExecuteCommandParams, InitializeParams, InitializeResult,
InitializedParams, MessageType, PublishDiagnosticsParams, Range, ServerCapabilities,
TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
TextDocumentSyncSaveOptions, Url,
};
use tower_lsp::{Client, LanguageServer};
use tracing::{error, info, instrument};
Expand All @@ -59,15 +35,15 @@ struct DocumentState {
document: Document,
ident_dict: Arc<FullDictionary>,
linter: LintGroup<MergedDictionary<FullDictionary>>,
language_id: Option<String>
language_id: Option<String>,
}

/// Deallocate
pub struct Backend {
client: Client,
static_dictionary: Arc<FullDictionary>,
config: RwLock<Config>,
doc_state: Mutex<HashMap<Url, DocumentState>>
doc_state: Mutex<HashMap<Url, DocumentState>>,
}

impl Backend {
Expand All @@ -78,7 +54,7 @@ impl Backend {
client,
static_dictionary: dictionary.into(),
doc_state: Mutex::new(HashMap::new()),
config: RwLock::new(config)
config: RwLock::new(config),
}
}

Expand Down Expand Up @@ -173,7 +149,7 @@ impl Backend {
#[instrument(skip(self))]
async fn generate_file_dictionary(
&self,
url: &Url
url: &Url,
) -> anyhow::Result<MergedDictionary<FullDictionary>> {
let (global_dictionary, file_dictionary) = tokio::join!(
self.generate_global_dictionary(),
Expand All @@ -190,11 +166,11 @@ impl Backend {
async fn update_document_from_file(
&self,
url: &Url,
language_id: Option<&str>
language_id: Option<&str>,
) -> anyhow::Result<()> {
let content = match tokio::fs::read_to_string(
url.to_file_path()
.map_err(|_| anyhow::format_err!("Could not extract file path."))?
.map_err(|_| anyhow::format_err!("Could not extract file path."))?,
)
.await
{
Expand All @@ -213,7 +189,7 @@ impl Backend {
&self,
url: &Url,
text: &str,
language_id: Option<&str>
language_id: Option<&str>,
) -> anyhow::Result<()> {
let mut doc_lock = self.doc_state.lock().await;
let config_lock = self.config.read().await;
Expand All @@ -225,7 +201,7 @@ impl Backend {
let mut doc_state = DocumentState {
linter: LintGroup::new(
config_lock.lint_config,
self.generate_file_dictionary(url).await?
self.generate_file_dictionary(url).await?,
),
language_id: language_id
.map(|v| v.to_string())
Expand Down Expand Up @@ -260,6 +236,8 @@ impl Backend {
Document::new(text, Box::new(Markdown))
} else if language_id == "gitcommit" {
Document::new(text, Box::new(GitCommitParser))
} else if language_id == "html" {
Document::new(text, Box::new(HtmlParser::new()))
} else if language_id == "mail" {
Document::new(text, Box::new(PlainEnglish))
} else {
Expand All @@ -276,7 +254,7 @@ impl Backend {
async fn generate_code_actions(
&self,
url: &Url,
range: Range
range: Range,
) -> Result<Vec<CodeActionOrCommand>> {
let (config, mut doc_states) = tokio::join!(self.config.read(), self.doc_state.lock());
let Some(doc_state) = doc_states.get_mut(url) else {
Expand Down Expand Up @@ -308,7 +286,7 @@ impl Backend {
actions.push(CodeActionOrCommand::Command(Command::new(
"Open URL".to_string(),
"HarperOpen".to_string(),
Some(vec![doc_state.document.get_span_content_str(span).into()])
Some(vec![doc_state.document.get_span_content_str(span).into()]),
)))
}

Expand All @@ -328,7 +306,7 @@ impl Backend {
lints_to_diagnostics(
doc_state.document.get_full_content(),
&lints,
config.diagnostic_severity
config.diagnostic_severity,
)
}

Expand All @@ -339,7 +317,7 @@ impl Backend {
let result = PublishDiagnosticsParams {
uri: url.clone(),
diagnostics,
version: None
version: None,
};

self.client
Expand Down Expand Up @@ -369,12 +347,11 @@ impl LanguageServer for Backend {
change: Some(TextDocumentSyncKind::FULL),
will_save: None,
will_save_wait_until: None,
save: Some(TextDocumentSyncSaveOptions::Supported(true))
}
save: Some(TextDocumentSyncSaveOptions::Supported(true)),
},
)),

..Default::default()
}
},
})
}

Expand Down Expand Up @@ -405,7 +382,7 @@ impl LanguageServer for Backend {
.update_document(
&params.text_document.uri,
&params.text_document.text,
Some(&params.text_document.language_id)
Some(&params.text_document.language_id),
)
.await;

Expand Down Expand Up @@ -494,7 +471,7 @@ impl LanguageServer for Backend {
error!("Unable to open URL: {}", err);
}
},
_ => ()
_ => (),
}

Ok(None)
Expand Down Expand Up @@ -525,7 +502,7 @@ impl LanguageServer for Backend {
// Update documents with new config
futures::future::join_all(
keys.iter()
.map(|key| self.update_document_from_file(key, None))
.map(|key| self.update_document_from_file(key, None)),
)
.await;
}
Expand Down

0 comments on commit 37be1f5

Please sign in to comment.