Skip to content

Commit

Permalink
Display inlay hints for label references
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Oct 30, 2023
1 parent 905e1e3 commit f5ce598
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 15 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Add `texlab.inlayHints.labelDefinitions` and `texlab.inlayHints.labelReferences` options ([#753](https://github.com/latex-lsp/texlab/issues/753))
- Display inlay hints for label references by default ([#753](https://github.com/latex-lsp/texlab/issues/753))

## [5.10.1] - 2023-10-10

### Fixed
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

17 changes: 17 additions & 0 deletions crates/base-db/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct Config {
pub symbols: SymbolConfig,
pub syntax: SyntaxConfig,
pub completion: CompletionConfig,
pub inlay_hints: InlayHintConfig,
}

#[derive(Debug)]
Expand Down Expand Up @@ -77,6 +78,12 @@ pub struct SymbolConfig {
pub ignored_patterns: Vec<Regex>,
}

#[derive(Debug)]
pub struct InlayHintConfig {
pub label_definitions: bool,
pub label_references: bool,
}

#[derive(Debug)]
pub struct CompletionConfig {
pub matcher: MatchingAlgo,
Expand All @@ -101,6 +108,7 @@ impl Default for Config {
symbols: SymbolConfig::default(),
syntax: SyntaxConfig::default(),
completion: CompletionConfig::default(),
inlay_hints: InlayHintConfig::default(),
}
}
}
Expand Down Expand Up @@ -174,6 +182,15 @@ impl Default for SymbolConfig {
}
}

impl Default for InlayHintConfig {
fn default() -> Self {
Self {
label_definitions: true,
label_references: true,
}
}
}

impl Default for CompletionConfig {
fn default() -> Self {
Self {
Expand Down
1 change: 1 addition & 0 deletions crates/inlay-hints/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.11"
rustc-hash = "1.1.0"
syntax = { path = "../syntax" }

[dev-dependencies]
Expand Down
56 changes: 43 additions & 13 deletions crates/inlay-hints/src/label.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,59 @@
use base_db::{semantics::tex::LabelKind, util::render_label};
use base_db::{
semantics::tex::{Label, LabelKind},
util::{queries::Object, render_label},
FeatureParams,
};
use rustc_hash::FxHashMap;

use crate::InlayHintData;

use super::InlayHintBuilder;
use crate::{InlayHint, InlayHintBuilder, InlayHintData};

pub(super) fn find_hints(builder: &mut InlayHintBuilder) -> Option<()> {
let definitions = base_db::semantics::tex::Label::find_all(&builder.params.feature.project)
.into_iter()
.filter(|(_, label)| label.kind == LabelKind::Definition)
.map(|(_, label)| (label.name_text(), label))
.collect::<FxHashMap<_, _>>();

let params = &builder.params.feature;
let data = params.document.data.as_tex()?;
let range = builder.params.range;
for label in data
.semantics
.labels
.iter()
.filter(|label| label.kind == LabelKind::Definition)
.filter(|label| label.name.range.intersect(range).is_some())
{
let Some(rendered) = render_label(params.workspace, &params.project, label) else {
continue;
};

builder.hints.push(crate::InlayHint {
offset: label.full_range.end(),
data: InlayHintData::LabelDefinition(rendered),
});
if let Some(hint) = process_label(params, &definitions, label) {
builder.hints.push(hint);
}
}

Some(())
}

fn process_label<'a>(
params: &FeatureParams<'a>,
definitions: &FxHashMap<&str, &'a Label>,
label: &'a Label,
) -> Option<InlayHint<'a>> {
let config = &params.workspace.config().inlay_hints;
let offset = label.full_range.end();
let data = if label.kind == LabelKind::Definition {
if !config.label_definitions {
return None;
}

let label = render_label(params.workspace, &params.project, label)?;
InlayHintData::LabelDefinition(label)
} else {
if !config.label_references {
return None;
}

let label = definitions.get(label.name.text.as_str())?;
let label = render_label(params.workspace, &params.project, label)?;
InlayHintData::LabelReference(label)
};

Some(InlayHint { offset, data })
}
1 change: 1 addition & 0 deletions crates/inlay-hints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct InlayHint<'a> {
#[derive(Debug, PartialEq, Eq)]
pub enum InlayHintData<'a> {
LabelDefinition(RenderedLabel<'a>),
LabelReference(RenderedLabel<'a>),
}

pub fn find_all<'a>(params: InlayHintParams<'a>) -> Option<Vec<InlayHint>> {
Expand Down
18 changes: 16 additions & 2 deletions crates/texlab/src/features/inlay_hint.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use base_db::{util::RenderedObject, FeatureParams, Workspace};
use inlay_hints::InlayHintParams;
use inlay_hints::{InlayHintData, InlayHintParams};

use crate::util::line_index_ext::LineIndexExt;

Expand All @@ -18,7 +18,7 @@ pub fn find_all(
let hints = hints.into_iter().filter_map(|hint| {
let position = line_index.line_col_lsp(hint.offset);
Some(match hint.data {
inlay_hints::InlayHintData::LabelDefinition(label) => {
InlayHintData::LabelDefinition(label) => {
let number = label.number?;

let text = match &label.object {
Expand All @@ -35,6 +35,20 @@ pub fn find_all(
RenderedObject::EnumItem => format!("Item {}", number),
};

lsp_types::InlayHint {
position,
label: lsp_types::InlayHintLabel::String(format!(" {text} ")),
kind: None,
text_edits: None,
tooltip: None,
padding_left: Some(true),
padding_right: None,
data: None,
}
}
InlayHintData::LabelReference(label) => {
let text = label.reference();

lsp_types::InlayHint {
position,
label: lsp_types::InlayHintLabel::String(format!(" {text} ")),
Expand Down
12 changes: 12 additions & 0 deletions crates/texlab/src/server/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct Options {
pub latexindent: LatexindentOptions,
pub forward_search: ForwardSearchOptions,
pub completion: CompletionOptions,
pub inlay_hints: InlayHintOptions,
pub experimental: ExperimentalOptions,
}

Expand Down Expand Up @@ -100,6 +101,14 @@ pub struct DiagnosticsOptions {
pub ignored_patterns: Vec<RegexPattern>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(default)]
pub struct InlayHintOptions {
pub label_definitions: Option<bool>,
pub label_references: Option<bool>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(default)]
Expand Down Expand Up @@ -243,6 +252,9 @@ impl From<Options> for Config {
.map(|pattern| pattern.0)
.collect();

config.inlay_hints.label_definitions = value.inlay_hints.label_definitions.unwrap_or(true);
config.inlay_hints.label_references = value.inlay_hints.label_references.unwrap_or(true);

config.completion.matcher = match value.completion.matcher {
CompletionMatcher::Fuzzy => base_db::MatchingAlgo::Skim,
CompletionMatcher::FuzzyIgnoreCase => base_db::MatchingAlgo::SkimIgnoreCase,
Expand Down

0 comments on commit f5ce598

Please sign in to comment.