use super::super::configuration::Configuration;
use super::token_finder::TokenFinder;
use jsonc_parser::CommentMap;
use jsonc_parser::ast::*;
use jsonc_parser::common::Ranged;
use std::collections::HashSet;
use text_lines::TextLines;
pub struct Context<'a, 'b> {
pub config: &'b Configuration,
pub text: &'b str,
pub text_info: TextLines,
pub is_jsonc: bool,
pub handled_comments: HashSet<usize>,
pub parent_stack: Vec<Node<'a, 'a>>,
pub current_node: Option<Node<'a, 'a>>,
pub comments: &'b CommentMap<'a>,
pub token_finder: TokenFinder<'a>,
}
impl<'a, 'b> Context<'a, 'b> {
pub fn has_handled_comment(&self, comment: &Comment) -> bool {
self.handled_comments.contains(&comment.start())
}
pub fn mark_comment_handled(&mut self, comment: &Comment) {
self.handled_comments.insert(comment.start());
}
pub fn start_line_with_comments(&mut self, node: &dyn Ranged) -> usize {
let start = node.start();
if let Some(leading_comments) = self.comments.get(&start) {
if let Some(previous_token) = self.token_finder.get_previous_token(node) {
let previous_end_line = self.text_info.line_index(previous_token.end());
let mut past_trailing_comments = false;
for comment in leading_comments.iter() {
let comment_start_line = self.text_info.line_index(comment.start());
if !past_trailing_comments && comment_start_line <= previous_end_line {
let comment_end_line = self.text_info.line_index(comment.end());
if comment_end_line > previous_end_line {
past_trailing_comments = true;
}
} else {
return comment_start_line;
}
}
self.text_info.line_index(node.start())
} else {
self
.text_info
.line_index(leading_comments.iter().next().unwrap().start())
}
} else {
self.text_info.line_index(node.start())
}
}
pub fn end_line_with_comments(&mut self, node: &dyn Ranged) -> usize {
let (search_end, previous_end_line) = self
.token_finder
.get_next_token_if_comma(node)
.map(|x| (x.end(), self.text_info.line_index(x.end())))
.unwrap_or((node.end(), self.text_info.line_index(node.end())));
if let Some(trailing_comments) = self.comments.get(&search_end) {
for comment in trailing_comments.iter() {
if comment.kind() == CommentKind::Line {
break;
}
let comment_start_line = self.text_info.line_index(comment.start());
if comment_start_line <= previous_end_line {
let comment_end_line = self.text_info.line_index(comment.end());
if comment_end_line > previous_end_line {
return comment_end_line; }
} else {
break;
}
}
}
previous_end_line
}
#[cfg(debug_assertions)]
pub fn assert_text(&self, start_pos: usize, end_pos: usize, expected_text: &str) {
let actual_text = &self.text[start_pos..end_pos];
if actual_text != expected_text {
panic!("Expected text `{}`, but found `{}`", expected_text, actual_text)
}
}
}