Skip to content

Commit

Permalink
Refactor "textDocument/documentHighlight" request
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Mar 12, 2020
1 parent 0ad310a commit 333a24f
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ impl FeatureTester {
.unwrap();
let doc = Document::open(DocumentParams {
uri,
text: text.clone(),
text: text.trim().into(),
language,
resolver: &resolver,
options: &options,
Expand Down
109 changes: 109 additions & 0 deletions src/highlight/latex_label.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use crate::{
feature::{FeatureProvider, FeatureRequest},
protocol::{DocumentHighlight, DocumentHighlightKind, RangeExt, TextDocumentPositionParams},
syntax::{latex, LatexLabelKind, SyntaxNode},
workspace::DocumentContent,
};
use futures_boxed::boxed;

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct LatexLabelHighlightProvider;

impl FeatureProvider for LatexLabelHighlightProvider {
type Params = TextDocumentPositionParams;
type Output = Vec<DocumentHighlight>;

#[boxed]
async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
let mut highlights = Vec::new();
if let DocumentContent::Latex(table) = &req.current().content {
if let Some(name) = table
.labels
.iter()
.flat_map(|label| label.names(&table.tree))
.find(|label| label.range().contains(req.params.position))
.map(latex::Token::text)
{
for label_group in &table.labels {
for label in label_group.names(&table.tree) {
if label.text() == name {
let kind = match label_group.kind {
LatexLabelKind::Definition => DocumentHighlightKind::Write,
LatexLabelKind::Reference(_) => DocumentHighlightKind::Read,
};

let highlight = DocumentHighlight {
range: label.range(),
kind: Some(kind),
};
highlights.push(highlight);
}
}
}
}
}
highlights
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{feature::FeatureTester, protocol::Range};
use indoc::indoc;

#[tokio::test]
async fn has_label() {
let actual_highlights = FeatureTester::new()
.file(
"foo.tex",
indoc!(
r#"
\label{foo}
\ref{foo}
"#
),
)
.main("foo.tex")
.position(0, 7)
.test_position(LatexLabelHighlightProvider)
.await;

let expected_highlights = vec![
DocumentHighlight {
range: Range::new_simple(0, 7, 0, 10),
kind: Some(DocumentHighlightKind::Write),
},
DocumentHighlight {
range: Range::new_simple(1, 5, 1, 8),
kind: Some(DocumentHighlightKind::Read),
},
];

assert_eq!(actual_highlights, expected_highlights);
}

#[tokio::test]
async fn no_label_latex() {
let actual_highlights = FeatureTester::new()
.file("foo.tex", "")
.main("foo.tex")
.position(0, 0)
.test_position(LatexLabelHighlightProvider)
.await;

assert!(actual_highlights.is_empty());
}

#[tokio::test]
async fn no_label_bibtex() {
let actual_highlights = FeatureTester::new()
.file("foo.bib", "")
.main("foo.bib")
.position(0, 0)
.test_position(LatexLabelHighlightProvider)
.await;

assert!(actual_highlights.is_empty());
}
}
39 changes: 39 additions & 0 deletions src/highlight/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
mod latex_label;

use self::latex_label::LatexLabelHighlightProvider;
use crate::{
feature::{ConcatProvider, FeatureProvider, FeatureRequest},
protocol::{DocumentHighlight, TextDocumentPositionParams},
};
use futures_boxed::boxed;

pub struct HighlightProvider {
provider: ConcatProvider<TextDocumentPositionParams, DocumentHighlight>,
}

impl HighlightProvider {
pub fn new() -> Self {
Self {
provider: ConcatProvider::new(vec![Box::new(LatexLabelHighlightProvider)]),
}
}
}

impl Default for HighlightProvider {
fn default() -> Self {
Self::new()
}
}

impl FeatureProvider for HighlightProvider {
type Params = TextDocumentPositionParams;
type Output = Vec<DocumentHighlight>;

#[boxed]
async fn execute<'a>(
&'a self,
request: &'a FeatureRequest<TextDocumentPositionParams>,
) -> Vec<DocumentHighlight> {
self.provider.execute(request).await
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod components;
pub mod config;
pub mod feature;
pub mod highlight;
pub mod jsonrpc;
pub mod link;
pub mod protocol;
Expand Down
15 changes: 12 additions & 3 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
components::COMPONENT_DATABASE,
config::ConfigManager,
feature::{DocumentView, FeatureProvider, FeatureRequest},
highlight::HighlightProvider,
jsonrpc::{server::Result, Middleware},
link::LinkProvider,
protocol::*,
Expand All @@ -23,6 +24,7 @@ pub struct LatexLspServer<C> {
config_manager: OnceCell<ConfigManager<C>>,
action_manager: ActionManager,
workspace: Workspace,
highlight_provider: HighlightProvider,
link_provider: LinkProvider,
}

Expand All @@ -38,6 +40,7 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {
config_manager: OnceCell::new(),
action_manager: ActionManager::default(),
workspace,
highlight_provider: HighlightProvider::new(),
link_provider: LinkProvider::new(),
}
}
Expand Down Expand Up @@ -168,7 +171,10 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {

#[jsonrpc_method("workspace/didChangeConfiguration", kind = "notification")]
pub async fn did_change_configuration(&self, params: DidChangeConfigurationParams) {
self.config_manager().push(params.settings).await;
let config_manager = self.config_manager();
config_manager.push(params.settings).await;
let options = config_manager.get().await;
self.workspace.reparse(&options).await;
}

#[jsonrpc_method("window/workDoneProgress/cancel", kind = "notification")]
Expand Down Expand Up @@ -208,9 +214,12 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {
#[jsonrpc_method("textDocument/documentHighlight", kind = "request")]
pub async fn document_highlight(
&self,
_params: TextDocumentPositionParams,
params: TextDocumentPositionParams,
) -> Result<Vec<DocumentHighlight>> {
Ok(Vec::new())
let req = self
.make_feature_request(params.text_document.as_uri(), params)
.await?;
Ok(self.highlight_provider.execute(&req).await)
}

#[jsonrpc_method("workspace/symbol", kind = "request")]
Expand Down
7 changes: 7 additions & 0 deletions src/test/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ pub trait TestLspClient {
#[boxed]
async fn did_change_configuration(&self, params: DidChangeConfigurationParams);

#[jsonrpc_method("textDocument/documentHighlight", kind = "request")]
#[boxed]
async fn document_highlight(
&self,
params: TextDocumentPositionParams,
) -> Result<Vec<DocumentHighlight>>;

#[jsonrpc_method("textDocument/documentLink", kind = "request")]
#[boxed]
async fn document_link(&self, params: DocumentLinkParams) -> Result<Vec<DocumentLink>>;
Expand Down
43 changes: 42 additions & 1 deletion src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,27 @@ impl TestBed {
self.client.did_change(params).await;
}

pub async fn push_options(&self) {
let options = self.server.options.lock().await.clone();
let params = DidChangeConfigurationParams {
settings: serde_json::to_value::<Options>(options).unwrap(),
};
self.client.did_change_configuration(params).await
}

pub async fn document_highlight(
&self,
relative_path: &str,
line: u64,
character: u64,
) -> Option<Vec<DocumentHighlight>> {
let params = TextDocumentPositionParams {
text_document: self.identifier(relative_path),
position: Position::new(line, character),
};
self.client.document_highlight(params).await.ok()
}

pub async fn document_link(&self, relative_path: &str) -> Option<Vec<DocumentLink>> {
let params = DocumentLinkParams {
text_document: self.identifier(relative_path),
Expand All @@ -314,7 +335,7 @@ impl Drop for TestBed {
}
}

pub static FULL_CAPABILITIES: ClientCapabilities = {
pub static PULL_CAPABILITIES: ClientCapabilities = {
ClientCapabilities {
experimental: None,
text_document: None,
Expand All @@ -331,3 +352,23 @@ pub static FULL_CAPABILITIES: ClientCapabilities = {
}),
}
};

pub static PUSH_CAPABILITIES: ClientCapabilities = {
ClientCapabilities {
experimental: None,
text_document: None,
window: None,
workspace: Some(WorkspaceClientCapabilities {
apply_edit: None,
configuration: None,
did_change_configuration: Some(GenericCapability {
dynamic_registration: Some(true),
}),
did_change_watched_files: None,
execute_command: None,
symbol: None,
workspace_edit: None,
workspace_folders: None,
}),
}
};
69 changes: 69 additions & 0 deletions tests/highlight.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use indoc::indoc;
use texlab::{
protocol::*,
test::{TestBedBuilder, PULL_CAPABILITIES},
};

#[tokio::test]
async fn empty_document() {
let mut test_bed = TestBedBuilder::new().file("main.tex", "").build().await;
test_bed.spawn();
test_bed.initialize(PULL_CAPABILITIES.clone()).await;
test_bed.open("main.tex").await;

let actual_highlights = test_bed.document_highlight("main.tex", 0, 0).await.unwrap();

test_bed.shutdown().await;

assert!(actual_highlights.is_empty());
}

#[tokio::test]
async fn label() {
let mut test_bed = TestBedBuilder::new()
.file(
"main.tex",
indoc!(
r#"
\label{foo}
\ref{foo}
"#
),
)
.build()
.await;
test_bed.spawn();
test_bed.initialize(PULL_CAPABILITIES.clone()).await;
test_bed.open("main.tex").await;

let actual_highlights = test_bed.document_highlight("main.tex", 0, 7).await.unwrap();

let expected_highlights = vec![
DocumentHighlight {
range: Range::new_simple(0, 7, 0, 10),
kind: Some(DocumentHighlightKind::Write),
},
DocumentHighlight {
range: Range::new_simple(1, 5, 1, 8),
kind: Some(DocumentHighlightKind::Read),
},
];

test_bed.shutdown().await;

assert_eq!(actual_highlights, expected_highlights);
}

#[tokio::test]
async fn unknown_file() {
let mut test_bed = TestBedBuilder::new().build().await;

test_bed.spawn();
test_bed.initialize(PULL_CAPABILITIES.clone()).await;

let actual_highlights = test_bed.document_highlight("main.tex", 0, 0).await;

test_bed.shutdown().await;

assert_eq!(actual_highlights, None);
}
Loading

0 comments on commit 333a24f

Please sign in to comment.