use cpp_code_analysis::file::coordinates::FileOffset;
use cpp_code_analysis::format::{self, FormatKind, FormatLiteral, PieceKind};
use cpp_code_analysis::{DiskFiles, FileView, Session};
use lsp_types::Hover;
use crate::handlers::hover::markdown;
pub fn format_string_hover(
session: &Session<DiskFiles>,
view: &FileView,
in_the_file: FileOffset,
) -> Option<Hover> {
if view.written_text().is_some() {
return None;
}
let config = super::config_for(session)?;
let literals = session.format_literals(view, &config);
let source = view.source.as_ref();
for literal in &literals {
if !literal.range.contain(in_the_file.get()) {
continue;
}
let text = source.get(literal.range.start_offset..literal.range.end_offset())?;
let at = in_the_file.get() - literal.range.start_offset;
let piece = literal
.pieces
.iter()
.find(|piece| piece.start <= at && at < piece.end)?;
return Some(markdown(the_popup(text, literal, piece)?));
}
None
}
fn the_popup(literal_text: &str, literal: &FormatLiteral, piece: &format::Piece) -> Option<String> {
let shown = literal_text.get(piece.start..piece.end)?;
let parts = format::describe(literal_text, literal.kind, piece);
if parts.is_empty() {
return None;
}
let mut text = format!(
"**`{shown}`** — {}\n\n",
what_it_is(piece.kind, literal.kind)
);
for (label, value) in parts {
text.push_str(&format!("- **{label}**: {value}\n"));
}
Some(text)
}
fn what_it_is(kind: PieceKind, grammar: FormatKind) -> &'static str {
match (kind, grammar) {
(PieceKind::Conversion, FormatKind::Std) => "a presentation type",
(PieceKind::Conversion, FormatKind::Printf) => "a `printf` conversion",
(PieceKind::Conversion, FormatKind::Scanf) => "a `scanf` conversion",
(PieceKind::Specifier | PieceKind::DynamicWidth, FormatKind::Std) => {
"a field's specification"
}
(PieceKind::Specifier | PieceKind::DynamicWidth, FormatKind::Printf) => {
"a `printf` conversion's flags, width and precision"
}
(PieceKind::Specifier | PieceKind::DynamicWidth, FormatKind::Scanf) => {
"a `scanf` conversion's width"
}
(PieceKind::Argument, _) => "an argument reference",
(PieceKind::Escape, FormatKind::Std) => "an escape — a literal brace",
(PieceKind::Escape, _) => "an escape — a literal `%`",
}
}