jsonpiler 0.10.1

a Json syntax programming language for Windows
Documentation
use super::super::*;
use crate::prelude::*;
impl Pos<Parser> {
  pub(crate) fn diagnostic(
    &self,
    pos: Position,
    msg: &str,
    severity: u8,
    unused: bool,
  ) -> JsonNoPos {
    let index = floor_char_boundary(&self.val.text, pos.offset as usize);
    let end = floor_char_boundary(&self.val.text, pos.end() as usize);
    let start = (0..index).rfind(|i| self.val.text.as_bytes()[*i] == b'\n').map_or(0, |st| st + 1);
    let line_slice = &self.val.text.get(start..index).unwrap_or_default();
    let start_col = line_slice.encode_utf16().count();
    let mut end_line = pos.line;
    let mut end_col = start_col;
    let text = &self.val.text.get(index..end).unwrap_or_default();
    let mut parts = text.split('\n');
    if let Some(first) = parts.next() {
      end_col += first.encode_utf16().count();
    }
    for part in parts {
      end_line += 1;
      end_col = part.encode_utf16().count();
    }
    let mut key_vals = vec![
      ("message".into(), escape_err_msg(msg)),
      ("range".into(), format_range((pos.line, start_col), (end_line, end_col))),
      ("severity".into(), IntN(severity as i64)),
    ];
    if unused {
      key_vals.push(("tags".into(), ArrayN(vec![IntN(1)])));
    }
    ObjectN(key_vals)
  }
}
impl Server {
  #[expect(clippy::print_stderr)]
  pub(crate) fn publish_errs(
    &mut self,
    uri: &str,
    err: &JsonpilerErr,
    diag_map: &mut BTreeMap<String, Vec<JsonNoPos>>,
    jsonpiler: &Jsonpiler,
  ) {
    eprintln!("{}", jsonpiler.format_err(err));
    let err_str = err.to_string();
    let pos_vec = err.pos_vec();
    if pos_vec.is_empty() {
      diag_map.entry(uri.to_owned()).or_default().push(ObjectN(vec![
        ("message".into(), escape_err_msg(&err_str)),
        ("range".into(), format_range((0, 0), (0, 0))),
      ]));
      return;
    }
    for pos in pos_vec.iter().rev() {
      let diag = jsonpiler.parsers[pos.file as usize].diagnostic(*pos, &err_str, 1, false);
      let pos_uri = path2uri(&jsonpiler.parsers[pos.file as usize].val.file);
      if let Some(dep_source) = self.sources.get_mut(&pos_uri) {
        dep_source.reload.insert(uri.to_owned());
      }
      diag_map.entry(pos_uri).or_default().push(diag);
    }
    if let Some(issue) = err.issue_msg() {
      self.notify(
        "window/showMessage",
        ObjectN(vec![("message".into(), StrN(issue)), ("type".into(), IntN(1))]),
      );
    }
  }
  pub(crate) fn update_source(&mut self, uri: &str) {
    let Some(mut source) = self.get_source(uri) else {
      self.clear_diag(uri.to_owned());
      self.sources.remove(uri);
      return;
    };
    let mut jsonpiler = Jsonpiler::new(true);
    for reload_uri in take(&mut source.reload) {
      if Path::new(&uri2path(&reload_uri)).exists() {
        self.update_source(&reload_uri)
      }
    }
    let mut first_parser =
      <Pos<Parser>>::new(take(&mut source.text), 0, uri2path(uri), jsonpiler.id());
    let parsed = first_parser.parse_jspl();
    jsonpiler.parsers.push(first_parser);
    let mut diag_map = BTreeMap::new();
    match parsed {
      Ok(json) => {
        source.parsed = Some(json.clone());
        if let Err(err) = jsonpiler.compile(json) {
          self.publish_errs(uri, &err, &mut diag_map, &jsonpiler);
        } else {
          diag_map.entry(uri.to_owned()).or_default();
        }
        source.analysis = take(&mut jsonpiler.analysis);
      }
      Err(err) => {
        source.parsed = None;
        source.analysis = None;
        self.publish_errs(uri, &err.into(), &mut diag_map, &jsonpiler)
      }
    }
    for warn in jsonpiler.parsers.iter().flat_map(|parser| &parser.val.warns) {
      let diag = jsonpiler.parsers[warn.pos.file as usize].diagnostic(
        warn.pos,
        &format!("{}", warn.val),
        2,
        matches!(warn.val, UnusedName(..)),
      );
      let pos_uri = path2uri(&jsonpiler.parsers[warn.pos.file as usize].val.file);
      diag_map.entry(pos_uri).or_default().push(diag);
    }
    for (diag_uri, diags) in diag_map {
      self.notify(
        "textDocument/publishDiagnostics",
        ObjectN(vec![
          ("uri".into(), StrN(diag_uri.clone())),
          ("diagnostics".into(), ArrayN(diags)),
        ]),
      );
    }
    let Ok(first_parser_mut) = jsonpiler.first_parser_mut() else {
      self.sources.remove(uri);
      return;
    };
    source.text = take(&mut first_parser_mut.val.text);
    self.sources.insert(uri.to_owned(), source);
  }
}
fn escape_err_msg(err_msg: &str) -> JsonNoPos {
  StrN(err_msg.replace("\n", " ").replace("  ", ""))
}