Skip to content

Commit

Permalink
Merge pull request #38 from WillLillis/hover_support
Browse files Browse the repository at this point in the history
Improve hover support
  • Loading branch information
ThePrimeagen committed Feb 11, 2024
2 parents 17ffbcd + 3432066 commit 0ad57f0
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 18 deletions.
10 changes: 5 additions & 5 deletions lsp/src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
};
use log::{debug, error, warn};
use lsp_server::{Message, Notification, Request, RequestId};
use lsp_types::{CompletionContext, CompletionParams, CompletionTriggerKind};
use lsp_types::{CompletionContext, CompletionParams, CompletionTriggerKind, HoverParams};

#[derive(serde::Deserialize, Debug)]
struct Text {
Expand Down Expand Up @@ -141,12 +141,12 @@ fn handle_completion(req: Request) -> Option<HtmxResult> {
}

fn handle_hover(req: Request) -> Option<HtmxResult> {
let completion: CompletionParams = serde_json::from_value(req.params).ok()?;
debug!("handle_hover: {:?}", completion.context);
let hover: HoverParams = serde_json::from_value(req.params).ok()?;
debug!("handle_hover: {:?}", hover);

let text_params = completion.text_document_position;
let text_params = hover.text_document_position_params;

debug!("handle_hover text_params: {:?}", text_params);
debug!("handle_hover text_position_params: {:?}", text_params);

let attribute = hx_hover(text_params)?;

Expand Down
14 changes: 10 additions & 4 deletions lsp/src/htmx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use log::debug;
use lsp_types::TextDocumentPositionParams;
use serde::{Deserialize, Serialize};

use crate::tree_sitter::Position;
use crate::{text_store::get_word_from_pos_params, tree_sitter::Position};

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HxCompletion {
Expand Down Expand Up @@ -39,12 +39,18 @@ pub fn hx_completion(text_params: TextDocumentPositionParams) -> Option<&'static
}

pub fn hx_hover(text_params: TextDocumentPositionParams) -> Option<HxCompletion> {
let result = crate::tree_sitter::get_position_from_lsp_completion(text_params.clone())?;
let result = match get_word_from_pos_params(&text_params) {
Ok(word) => Position::AttributeName(word),
Err(_) => {
return None;
}
};
debug!("handle_hover result: {:?}", result);

match result {
Position::AttributeName(name) => HX_TAGS.iter().find(|x| x.name == name).cloned(),
Position::AttributeValue { name, .. } => HX_TAGS.iter().find(|x| x.name == name).cloned(),
Position::AttributeName(name) | Position::AttributeValue { name, .. } => {
HX_TAGS.iter().find(|x| x.name == name).cloned()
}
}
}

Expand Down
12 changes: 6 additions & 6 deletions lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use htmx::HxCompletion;
use log::{debug, error, info, warn};
use lsp_types::{
CompletionItem, CompletionItemKind, CompletionList, HoverContents, InitializeParams,
LanguageString, MarkedString, ServerCapabilities, TextDocumentSyncCapability,
TextDocumentSyncKind, WorkDoneProgressOptions,
MarkupContent, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
WorkDoneProgressOptions,
};

use lsp_server::{Connection, Message, Response};
Expand Down Expand Up @@ -80,10 +80,10 @@ fn main_loop(connection: Connection, params: serde_json::Value) -> Result<()> {
Some(HtmxResult::AttributeHover(hover_resp)) => {
debug!("main_loop - hover response: {:?}", hover_resp);
let hover_response = lsp_types::Hover {
contents: HoverContents::Scalar(MarkedString::LanguageString(LanguageString {
language: "html".to_string(),
value: hover_resp.value.clone(),
})),
contents: HoverContents::Markup(MarkupContent {
kind: lsp_types::MarkupKind::Markdown,
value: hover_resp.value.to_string(),
}),
range: None,
};

Expand Down
54 changes: 52 additions & 2 deletions lsp/src/text_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
sync::{Arc, Mutex, OnceLock},
};

use lsp_types::Url;
use lsp_types::{TextDocumentPositionParams, Url};

type TxtStore = HashMap<String, String>;

Expand All @@ -29,7 +29,7 @@ pub fn init_text_store() {
_ = TEXT_STORE.set(Arc::new(Mutex::new(TextStore(HashMap::new()))));
}

pub fn get_text_document(uri: Url) -> Option<String> {
pub fn get_text_document(uri: &Url) -> Option<String> {
return TEXT_STORE
.get()
.expect("text store not initialized")
Expand All @@ -38,3 +38,53 @@ pub fn get_text_document(uri: Url) -> Option<String> {
.get(&uri.to_string())
.cloned();
}

/// Find the start and end indices of a word inside the given line
/// Borrowed from RLS
fn find_word_at_pos(line: &str, col: usize) -> (usize, usize) {
let line_ = format!("{} ", line);
let is_ident_char = |c: char| c.is_alphanumeric() || c == '_' || c == '-';

let start = line_
.chars()
.enumerate()
.take(col)
.filter(|&(_, c)| !is_ident_char(c))
.last()
.map(|(i, _)| i + 1)
.unwrap_or(0);

#[allow(clippy::filter_next)]
let mut end = line_
.chars()
.enumerate()
.skip(col)
.filter(|&(_, c)| !is_ident_char(c));

let end = end.next();
(start, end.map(|(i, _)| i).unwrap_or(col))
}

pub fn get_word_from_pos_params(pos_params: &TextDocumentPositionParams) -> anyhow::Result<String> {
let uri = &pos_params.text_document.uri;
let line = pos_params.position.line as usize;
let col = pos_params.position.character as usize;

match get_text_document(uri) {
Some(text) => {
let line_conts = match text.lines().nth(line) {
Some(conts) => conts,
None => {
return Err(anyhow::anyhow!(
"get_word_from_pos_params Failed to get word under cursor"
));
}
};
let (start, end) = find_word_at_pos(line_conts, col);
Ok(String::from(&line_conts[start..end]))
}
None => Err(anyhow::anyhow!(
"get_word_from_pos_params Failed to get word under cursor"
)),
}
}
2 changes: 1 addition & 1 deletion lsp/src/tree_sitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub fn get_position_from_lsp_completion(
text_params: TextDocumentPositionParams,
) -> Option<Position> {
error!("get_position_from_lsp_completion");
let text = get_text_document(text_params.text_document.uri)?;
let text = get_text_document(&text_params.text_document.uri)?;
error!("get_position_from_lsp_completion: text {}", text);
let pos = text_params.position;
error!("get_position_from_lsp_completion: pos {:?}", pos);
Expand Down

0 comments on commit 0ad57f0

Please sign in to comment.