1use std::{cell::RefCell, fmt};
2
3use flux_arc_interner::{Internable, Interned};
4use flux_common::index::IndexGen;
5use flux_config as config;
6use rustc_abi::FieldIdx;
7use rustc_data_structures::unord::UnordMap;
8use rustc_hash::FxHashSet;
9use rustc_hir::def_id::DefId;
10use rustc_index::newtype_index;
11use rustc_middle::ty::TyCtxt;
12use rustc_span::{Pos, Span};
13use rustc_type_ir::{BoundVar, DebruijnIndex, INNERMOST};
14use serde::Serialize;
15
16#[macro_export]
17macro_rules! _with_cx {
18 ($cx:expr, $e:expr) => {
19 $crate::pretty::WithCx::new($cx, $e)
20 };
21}
22pub use crate::_with_cx as with_cx;
23use crate::def_id::{FluxDefId, FluxLocalDefId};
24
25#[macro_export]
26macro_rules! _format_args_cx {
27 ($cx:ident, $fmt:literal, $($args:tt)*) => {
28 $crate::_format_args_cx!(@go ($cx, $fmt; $($args)*) -> ())
29 };
30 ($cx:expr, $fmt:literal) => {
31 format_args!($fmt)
32 };
33 (@go ($cx:ident, $fmt:literal; ^$head:expr, $($tail:tt)*) -> ($($accum:tt)*)) => {
34 $crate::_format_args_cx!(@go ($cx, $fmt; $($tail)*) -> ($($accum)* $head,))
35 };
36 (@go ($cx:ident, $fmt:literal; $head:expr, $($tail:tt)*) -> ($($accum:tt)*)) => {
37 $crate::_format_args_cx!(@go ($cx, $fmt; $($tail)*) -> ($($accum)* $crate::pretty::with_cx!($cx, $head),))
38 };
39 (@go ($cx:ident, $fmt:literal; ^$head:expr) -> ($($accum:tt)*)) => {
40 $crate::_format_args_cx!(@as_expr format_args!($fmt, $($accum)* $head,))
41 };
42 (@go ($cx:ident, $fmt:literal; $head:expr) -> ($($accum:tt)*)) => {
43 $crate::_format_args_cx!(@as_expr format_args!($fmt, $($accum)* $crate::pretty::with_cx!($cx, $head),))
44 };
45 (@as_expr $e:expr) => { $e };
46}
47pub use crate::_format_args_cx as format_args_cx;
48
49#[macro_export]
50macro_rules! _format_cx {
51 ($($arg:tt)*) => {
52 std::fmt::format($crate::_format_args_cx!($($arg)*))
53 }
54}
55pub use crate::_format_cx as format_cx;
56
57#[macro_export]
58macro_rules! _w {
59 ($cx:expr, $f:expr, $fmt:literal, $($args:tt)*) => {{
60 #[allow(unused_variables)]
61 let cx = $cx;
62 $f.write_fmt($crate::_format_args_cx!(cx, $fmt, $($args)*))
63 }};
64 ($cx:expr, $f:expr, $fmt:literal) => {
65 $f.write_fmt($crate::_format_args_cx!($cx, $fmt))
66 };
67}
68pub use crate::_w as w;
69
70#[macro_export]
71macro_rules! _join {
72 ($sep:expr, $iter:expr) => {
73 $crate::pretty::Join::new($sep, $iter)
74 };
75}
76pub use crate::_join as join;
77
78#[macro_export]
79macro_rules! _parens {
80 ($val:expr, $parenthesize:expr) => {
81 $crate::pretty::Parens::new(&$val, $parenthesize)
82 };
83}
84pub use crate::_parens as parens;
85
86#[macro_export]
87macro_rules! _impl_debug_with_default_cx {
88 ($($ty:ty $(=> $key:literal)?),* $(,)?) => {$(
89 impl std::fmt::Debug for $ty {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 #[allow(unused_mut, unused_assignments)]
92 let mut key = None;
93 $(
94 key = Some($key);
95 )?
96 $crate::pretty::pprint_with_default_cx(f, self, key)
97 }
98 }
99 )*};
100}
101
102pub fn pprint_with_default_cx<T: Pretty>(
103 f: &mut std::fmt::Formatter<'_>,
104 t: &T,
105 cfg_key: Option<&'static str>,
106) -> std::fmt::Result {
107 rustc_middle::ty::tls::with(|tcx| {
108 #[allow(unused_mut)]
109 let mut cx = <T>::default_cx(tcx);
110
111 if let Some(pprint) = flux_config::CONFIG_FILE
112 .get("dev")
113 .and_then(|dev| dev.get("pprint"))
114 {
115 if let Some(opts) = pprint.get("default") {
116 cx.merge(opts);
117 }
118
119 if let Some(key) = cfg_key
120 && let Some(opts) = pprint.get(key)
121 {
122 cx.merge(opts);
123 }
124 }
125
126 if let Some(key) = cfg_key
127 && let Some(opts) = flux_config::CONFIG_FILE
128 .get("dev")
129 .and_then(|dev| dev.get("pprint"))
130 .and_then(|pprint| pprint.get(key))
131 {
132 cx.merge(opts);
133 }
134 Pretty::fmt(t, &cx, f)
135 })
136}
137
138pub use crate::_impl_debug_with_default_cx as impl_debug_with_default_cx;
139use crate::{
140 global_env::GlobalEnv,
141 rty::{
142 AdtSortDef, BoundReft, BoundReftKind, BoundVariableKind, EarlyReftParam, Name, PrettyMap,
143 },
144};
145
146#[derive(Copy, Clone)]
147pub enum KVarArgs {
148 All,
149 SelfOnly,
150 Hide,
151}
152
153#[derive(Clone, Copy)]
154pub enum GenvOrTcx<'genv, 'tcx> {
155 Genv(GlobalEnv<'genv, 'tcx>),
156 Tcx(TyCtxt<'tcx>),
157}
158
159impl<'genv, 'tcx> GenvOrTcx<'genv, 'tcx> {
160 fn tcx(self) -> TyCtxt<'tcx> {
161 match self {
162 GenvOrTcx::Genv(genv) => genv.tcx(),
163 GenvOrTcx::Tcx(tcx) => tcx,
164 }
165 }
166
167 fn genv(self) -> Option<GlobalEnv<'genv, 'tcx>> {
168 match self {
169 GenvOrTcx::Genv(genv) => Some(genv),
170 GenvOrTcx::Tcx(_) => None,
171 }
172 }
173}
174
175impl<'tcx> From<TyCtxt<'tcx>> for GenvOrTcx<'_, 'tcx> {
176 fn from(v: TyCtxt<'tcx>) -> Self {
177 Self::Tcx(v)
178 }
179}
180
181impl<'genv, 'tcx> From<GlobalEnv<'genv, 'tcx>> for GenvOrTcx<'genv, 'tcx> {
182 fn from(v: GlobalEnv<'genv, 'tcx>) -> Self {
183 Self::Genv(v)
184 }
185}
186
187pub struct PrettyCx<'genv, 'tcx> {
188 pub cx: GenvOrTcx<'genv, 'tcx>,
189 pub kvar_args: KVarArgs,
190 pub fully_qualified_paths: bool,
191 pub simplify_exprs: bool,
192 pub tags: bool,
193 pub bindings_chain: bool,
194 pub preds_chain: bool,
195 pub full_spans: bool,
196 pub hide_uninit: bool,
197 pub hide_refinements: bool,
198 pub hide_regions: bool,
199 pub hide_sorts: bool,
200 pub pretty_var_env: PrettyMap<Name>,
201 pub bvar_env: BoundVarEnv,
202 pub earlyparam_env: RefCell<Option<EarlyParamEnv>>,
203}
204
205macro_rules! set_opts {
206 ($cx:expr, $opts:expr, [$($opt:ident),+ $(,)?]) => {
207 $(
208 if let Some(val) = $opts.get(stringify!($opt)).and_then(|v| FromOpt::from_opt(v)) {
209 $cx.$opt = val;
210 }
211 )+
212 };
213}
214
215impl<'genv, 'tcx> PrettyCx<'genv, 'tcx> {
216 pub fn default(cx: impl Into<GenvOrTcx<'genv, 'tcx>>) -> Self {
217 PrettyCx {
218 cx: cx.into(),
219 kvar_args: KVarArgs::SelfOnly,
220 fully_qualified_paths: false,
221 simplify_exprs: true,
222 tags: true,
223 bindings_chain: true,
224 preds_chain: true,
225 full_spans: false,
226 hide_uninit: true,
227 hide_refinements: false,
228 hide_regions: false,
229 hide_sorts: true,
230 pretty_var_env: PrettyMap::new(),
231 bvar_env: BoundVarEnv::default(),
232 earlyparam_env: RefCell::new(None),
233 }
234 }
235
236 pub fn tcx(&self) -> TyCtxt<'tcx> {
237 self.cx.tcx()
238 }
239
240 pub fn genv(&self) -> Option<GlobalEnv<'genv, 'tcx>> {
241 self.cx.genv()
242 }
243
244 pub fn adt_sort_def_of(&self, def_id: DefId) -> Option<AdtSortDef> {
245 self.genv()
246 .and_then(|genv| genv.adt_sort_def_of(def_id).ok())
247 }
248
249 pub fn merge(&mut self, opts: &config::Value) {
250 set_opts!(
251 self,
252 opts,
253 [
254 kvar_args,
255 fully_qualified_paths,
256 simplify_exprs,
257 tags,
258 bindings_chain,
259 preds_chain,
260 full_spans,
261 hide_uninit,
262 hide_refinements,
263 hide_regions,
264 hide_sorts,
265 ]
266 );
267 }
268
269 pub fn with_bound_vars<R>(&self, vars: &[BoundVariableKind], f: impl FnOnce() -> R) -> R {
270 self.bvar_env.push_layer(vars, FxHashSet::default(), None);
271 let r = f();
272 self.bvar_env.pop_layer();
273 r
274 }
275
276 pub fn with_bound_vars_removable<R1, R2>(
277 &self,
278 vars: &[BoundVariableKind],
279 vars_to_remove: FxHashSet<BoundVar>,
280 fn_root_layer_type: Option<FnRootLayerType>,
281 fmt_body: impl FnOnce(&mut String) -> Result<R1, fmt::Error>,
282 fmt_vars_with_body: impl FnOnce(R1, BoundVarLayer, String) -> Result<R2, fmt::Error>,
283 ) -> Result<R2, fmt::Error> {
284 self.bvar_env
285 .push_layer(vars, vars_to_remove, fn_root_layer_type);
286 let mut body = String::new();
287 let r1 = fmt_body(&mut body)?;
288 let r2 = fmt_vars_with_body(r1, self.bvar_env.peek_layer().unwrap(), body)?;
295 self.bvar_env.pop_layer();
296 Ok(r2)
297 }
298
299 pub fn fmt_bound_vars(
300 &self,
301 print_infer_mode: bool,
302 left: &str,
303 vars: &[BoundVariableKind],
304 right: &str,
305 f: &mut impl fmt::Write,
306 ) -> fmt::Result {
307 w!(self, f, "{left}")?;
308 for (i, var) in vars.iter().enumerate() {
309 if i > 0 {
310 w!(self, f, ", ")?;
311 }
312 match var {
313 BoundVariableKind::Region(re) => w!(self, f, "{:?}", re)?,
314 BoundVariableKind::Refine(sort, mode, BoundReftKind::Named(name)) => {
315 if print_infer_mode {
316 w!(self, f, "{}", ^mode.prefix_str())?;
317 }
318 w!(self, f, "{}", ^name)?;
319 if !self.hide_sorts {
320 w!(self, f, ": {:?}", sort)?;
321 }
322 }
323 BoundVariableKind::Refine(sort, mode, BoundReftKind::Anon) => {
324 if print_infer_mode {
325 w!(self, f, "{}", ^mode.prefix_str())?;
326 }
327 if let Some(name) = self.bvar_env.lookup(INNERMOST, BoundVar::from_usize(i)) {
328 w!(self, f, "{:?}", ^name)?;
329 } else {
330 w!(self, f, "_")?;
331 }
332 if !self.hide_sorts {
333 w!(self, f, ": {:?}", sort)?;
334 }
335 }
336 }
337 }
338 w!(self, f, "{right}")
339 }
340
341 pub fn fmt_bound_reft(
342 &self,
343 debruijn: DebruijnIndex,
344 breft: BoundReft,
345 f: &mut fmt::Formatter<'_>,
346 ) -> fmt::Result {
347 match breft.kind {
348 BoundReftKind::Anon => {
349 if let Some(name) = self.bvar_env.lookup(debruijn, breft.var) {
350 w!(self, f, "{name:?}")
351 } else {
352 w!(self, f, "⭡{}/#{:?}", ^debruijn.as_usize(), ^breft.var)
353 }
354 }
355 BoundReftKind::Named(name) => {
356 w!(self, f, "{name}")
357 }
358 }
359 }
360
361 pub fn with_early_params<R>(&self, f: impl FnOnce() -> R) -> R {
362 assert!(self.earlyparam_env.borrow().is_none(), "Already in an early param env");
363 *self.earlyparam_env.borrow_mut() = Some(FxHashSet::default());
364 let r = f();
365 *self.earlyparam_env.borrow_mut() = None;
366 r
367 }
368
369 pub fn kvar_args(self, kvar_args: KVarArgs) -> Self {
370 Self { kvar_args, ..self }
371 }
372
373 pub fn fully_qualified_paths(self, b: bool) -> Self {
374 Self { fully_qualified_paths: b, ..self }
375 }
376
377 pub fn hide_regions(self, b: bool) -> Self {
378 Self { hide_regions: b, ..self }
379 }
380
381 pub fn hide_sorts(self, b: bool) -> Self {
382 Self { hide_sorts: b, ..self }
383 }
384
385 pub fn hide_refinements(self, b: bool) -> Self {
386 Self { hide_refinements: b, ..self }
387 }
388
389 pub fn show_kvar_args(self) -> Self {
390 Self { kvar_args: KVarArgs::All, ..self }
391 }
392
393 pub fn nested_with_bound_vars(
394 &self,
395 left: &str,
396 vars: &[BoundVariableKind],
397 right: Option<String>,
398 f: impl FnOnce(String) -> Result<NestedString, fmt::Error>,
399 ) -> Result<NestedString, fmt::Error> {
400 let mut buffer = String::new();
401 self.with_bound_vars(vars, || {
402 if !vars.is_empty() {
403 let right = right.unwrap_or(". ".to_string());
404 self.fmt_bound_vars(false, left, vars, &right, &mut buffer)?;
405 }
406 f(buffer)
407 })
408 }
409}
410
411newtype_index! {
412 #[debug_format = "b{}"]
414 pub struct BoundVarName {}
415}
416
417#[derive(Copy, Clone)]
418pub enum FnRootLayerType {
419 FnArgs,
420 FnRet,
421}
422
423#[derive(Clone)]
424pub struct FnRootLayerMap {
425 pub name_map: UnordMap<BoundVar, BoundVarName>,
426 pub seen_vars: FxHashSet<BoundVar>,
427 pub layer_type: FnRootLayerType,
428}
429
430#[derive(Clone)]
431pub struct BoundVarLayer {
432 pub layer_map: BoundVarLayerMap,
433 pub vars_to_remove: FxHashSet<BoundVar>,
434 pub successfully_removed_vars: FxHashSet<BoundVar>,
435}
436
437#[derive(Clone)]
438pub enum BoundVarLayerMap {
439 LayerMap(UnordMap<BoundVar, BoundVarName>),
440 FnRootLayerMap(FnRootLayerMap),
456}
457
458impl BoundVarLayerMap {
459 fn name_map(&self) -> &UnordMap<BoundVar, BoundVarName> {
460 match self {
461 Self::LayerMap(name_map) => name_map,
462 Self::FnRootLayerMap(root_layer) => &root_layer.name_map,
463 }
464 }
465}
466
467#[derive(Default)]
468pub struct BoundVarEnv {
469 name_gen: IndexGen<BoundVarName>,
470 layers: RefCell<Vec<BoundVarLayer>>,
471}
472
473impl BoundVarEnv {
474 pub fn check_if_seen_fn_root_bvar(
482 &self,
483 debruijn: DebruijnIndex,
484 var: BoundVar,
485 ) -> Option<(bool, FnRootLayerType)> {
486 let num_layers = self.layers.borrow().len();
487 let mut layer = self.layers.borrow_mut();
488 match layer.get_mut(num_layers.checked_sub(debruijn.as_usize() + 1)?)? {
489 BoundVarLayer {
490 layer_map: BoundVarLayerMap::FnRootLayerMap(fn_root_layer), ..
491 } => Some((!fn_root_layer.seen_vars.insert(var), fn_root_layer.layer_type)),
492 _ => None,
493 }
494 }
495
496 pub fn should_remove_var(&self, debruijn: DebruijnIndex, var: BoundVar) -> Option<bool> {
497 let layers = self.layers.borrow();
498 Some(
499 layers
500 .get(layers.len().checked_sub(debruijn.as_usize() + 1)?)?
501 .vars_to_remove
502 .contains(&var),
503 )
504 }
505
506 pub fn mark_var_as_removed(&self, debruijn: DebruijnIndex, var: BoundVar) -> Option<bool> {
507 let mut layers = self.layers.borrow_mut();
508 let layer_index = layers.len().checked_sub(debruijn.as_usize() + 1)?;
509 Some(
510 layers
511 .get_mut(layer_index)?
512 .successfully_removed_vars
513 .insert(var),
514 )
515 }
516
517 fn lookup(&self, debruijn: DebruijnIndex, var: BoundVar) -> Option<BoundVarName> {
518 let layers = self.layers.borrow();
519 layers
520 .get(layers.len().checked_sub(debruijn.as_usize() + 1)?)?
521 .layer_map
522 .name_map()
523 .get(&var)
524 .copied()
525 }
526
527 fn push_layer(
528 &self,
529 vars: &[BoundVariableKind],
530 vars_to_remove: FxHashSet<BoundVar>,
531 is_fn_root_layer: Option<FnRootLayerType>,
532 ) {
533 let mut name_map = UnordMap::default();
534 for (idx, var) in vars.iter().enumerate() {
535 if let BoundVariableKind::Refine(_, _, BoundReftKind::Anon) = var {
536 name_map.insert(BoundVar::from_usize(idx), self.name_gen.fresh());
537 }
538 }
539 let layer_map = if let Some(layer_type) = is_fn_root_layer {
540 BoundVarLayerMap::FnRootLayerMap(FnRootLayerMap {
541 name_map,
542 seen_vars: FxHashSet::default(),
543 layer_type,
544 })
545 } else {
546 BoundVarLayerMap::LayerMap(name_map)
547 };
548 let layer = BoundVarLayer {
549 layer_map,
550 vars_to_remove,
551 successfully_removed_vars: FxHashSet::default(),
552 };
553 self.layers.borrow_mut().push(layer);
554 }
555
556 fn peek_layer(&self) -> Option<BoundVarLayer> {
557 self.layers.borrow().last().cloned()
558 }
559
560 fn pop_layer(&self) -> Option<BoundVarLayer> {
561 self.layers.borrow_mut().pop()
562 }
563}
564
565type EarlyParamEnv = FxHashSet<EarlyReftParam>;
566
567pub struct WithCx<'a, 'genv, 'tcx, T> {
568 data: T,
569 cx: &'a PrettyCx<'genv, 'tcx>,
570}
571
572pub struct Join<'a, I> {
573 sep: &'a str,
574 iter: RefCell<Option<I>>,
575}
576
577pub struct Parens<'a, T> {
578 val: &'a T,
579 parenthesize: bool,
580}
581
582pub trait Pretty {
583 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result;
584
585 fn default_cx(tcx: TyCtxt) -> PrettyCx {
586 PrettyCx::default(tcx)
587 }
588}
589
590impl Pretty for String {
591 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592 write!(f, "{self}")
593 }
594}
595
596impl<'a, I> Join<'a, I> {
597 pub fn new<T: IntoIterator<IntoIter = I>>(sep: &'a str, iter: T) -> Self {
598 Self { sep, iter: RefCell::new(Some(iter.into_iter())) }
599 }
600}
601
602impl<'a, T> Parens<'a, T> {
603 pub fn new(val: &'a T, parenthesize: bool) -> Self {
604 Self { val, parenthesize }
605 }
606}
607
608impl<'a, 'genv, 'tcx, T> WithCx<'a, 'genv, 'tcx, T> {
609 pub fn new(cx: &'a PrettyCx<'genv, 'tcx>, data: T) -> Self {
610 Self { data, cx }
611 }
612}
613
614impl<T: Pretty + ?Sized> Pretty for &'_ T {
615 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616 <T as Pretty>::fmt(self, cx, f)
617 }
618}
619
620impl<T: Pretty + Internable> Pretty for Interned<T> {
621 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
622 <T as Pretty>::fmt(self, cx, f)
623 }
624}
625
626impl<T, I> fmt::Debug for Join<'_, I>
627where
628 T: fmt::Debug,
629 I: Iterator<Item = T>,
630{
631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632 let Some(iter) = self.iter.borrow_mut().take() else {
633 panic!("Join: was already formatted once")
634 };
635 for (i, item) in iter.enumerate() {
636 if i > 0 {
637 write!(f, "{}", self.sep)?;
638 }
639 <T as fmt::Debug>::fmt(&item, f)?;
640 }
641 Ok(())
642 }
643}
644
645impl<T, I> Pretty for Join<'_, I>
646where
647 T: Pretty,
648 I: Iterator<Item = T>,
649{
650 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651 let Some(iter) = self.iter.borrow_mut().take() else {
652 panic!("Join: was already formatted once")
653 };
654 for (i, item) in iter.enumerate() {
655 if i > 0 {
656 write!(f, "{}", self.sep)?;
657 }
658 <T as Pretty>::fmt(&item, cx, f)?;
659 }
660 Ok(())
661 }
662}
663impl<T> Pretty for Parens<'_, T>
664where
665 T: Pretty,
666{
667 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
668 if self.parenthesize {
669 write!(f, "(")?;
670 }
671 <T as Pretty>::fmt(self.val, cx, f)?;
672 if self.parenthesize {
673 write!(f, ")")?;
674 }
675 Ok(())
676 }
677}
678
679impl<T: Pretty> fmt::Debug for WithCx<'_, '_, '_, T> {
680 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
681 <T as Pretty>::fmt(&self.data, self.cx, f)
682 }
683}
684
685impl Pretty for DefId {
686 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
687 if cx.fully_qualified_paths {
688 w!(cx, f, "{}", ^cx.tcx().def_path_str(self))
689 } else {
690 let path = cx.tcx().def_path(*self);
691 w!(cx, f, "{}", ^path.data.last().unwrap().as_sym(false))
692 }
693 }
694}
695
696impl Pretty for FluxDefId {
697 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
698 if cx.fully_qualified_paths {
699 w!(cx, f, "{:?}::{}", self.parent(), ^self.name())
700 } else {
701 w!(cx, f, "{}", ^self.name())
702 }
703 }
704}
705
706impl Pretty for FluxLocalDefId {
707 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708 w!(cx, f, "{:?}", self.to_def_id())
709 }
710}
711
712impl Pretty for FieldIdx {
713 fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
714 write!(f, "{}", self.as_u32())
715 }
716}
717
718impl Pretty for Span {
719 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
720 if cx.full_spans {
721 write!(f, "{self:?}")
722 } else {
723 let src_map = cx.tcx().sess.source_map();
724 let lo = src_map.lookup_char_pos(self.lo());
725 let hi = src_map.lookup_char_pos(self.hi());
726 write!(
749 f,
750 "{}:{}: {}:{}",
751 lo.line,
752 lo.col.to_usize() + 1,
753 hi.line,
754 hi.col.to_usize() + 1,
755 )
756 }
757 }
758}
759
760trait FromOpt: Sized {
761 fn from_opt(opt: &config::Value) -> Option<Self>;
762}
763
764impl FromOpt for bool {
765 fn from_opt(opt: &config::Value) -> Option<Self> {
766 opt.as_bool()
767 }
768}
769
770impl FromOpt for KVarArgs {
771 fn from_opt(opt: &config::Value) -> Option<Self> {
772 match opt.as_str() {
773 Some("self") => Some(KVarArgs::SelfOnly),
774 Some("hide") => Some(KVarArgs::Hide),
775 Some("all") => Some(KVarArgs::All),
776 _ => None,
777 }
778 }
779}
780
781#[derive(Serialize, Debug)]
784pub struct NestedString {
785 pub text: String,
786 pub key: Option<String>,
787 pub children: Option<Vec<NestedString>>,
788}
789
790pub fn debug_nested<T: Pretty>(cx: &PrettyCx, t: &T) -> Result<NestedString, fmt::Error> {
791 let t = WithCx::new(cx, t);
792 let text = format!("{t:?}");
793 Ok(NestedString { text, children: None, key: None })
794}
795
796pub fn float_children(children: Vec<Option<Vec<NestedString>>>) -> Option<Vec<NestedString>> {
797 let mut childrens: Vec<_> = children.into_iter().flatten().collect();
798 if childrens.is_empty() {
799 None
800 } else if childrens.len() == 1 {
801 let c = childrens.pop().unwrap();
802 Some(c)
803 } else {
804 let mut res = vec![];
805 for (i, children) in childrens.into_iter().enumerate() {
806 res.push(NestedString { text: format!("arg{i}"), children: Some(children), key: None });
807 }
808 Some(res)
809 }
810}
811
812pub trait PrettyNested {
813 fn fmt_nested(&self, cx: &PrettyCx) -> Result<NestedString, fmt::Error>;
814
815 fn nested_string(&self, cx: &PrettyCx) -> String {
816 let res = self.fmt_nested(cx).unwrap();
817 serde_json::to_string(&res).unwrap()
818 }
819}