rustfmt'd the codebase
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt::Display;
|
||||
use ariadne::Color;
|
||||
use ariadne::{Report, ReportKind};
|
||||
use rand::TryRng;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::procio::RedirGuard;
|
||||
use crate::{
|
||||
@@ -15,96 +15,96 @@ use crate::{
|
||||
pub type ShResult<T> = Result<T, ShErr>;
|
||||
|
||||
pub struct ColorRng {
|
||||
last_color: Option<Color>,
|
||||
last_color: Option<Color>,
|
||||
}
|
||||
|
||||
impl ColorRng {
|
||||
fn get_colors() -> &'static [Color] {
|
||||
&[
|
||||
Color::Red,
|
||||
Color::Cyan,
|
||||
Color::Blue,
|
||||
Color::Green,
|
||||
Color::Yellow,
|
||||
Color::Magenta,
|
||||
Color::Fixed(208), // orange
|
||||
Color::Fixed(39), // deep sky blue
|
||||
Color::Fixed(170), // orchid / magenta-pink
|
||||
Color::Fixed(76), // chartreuse
|
||||
Color::Fixed(51), // aqua
|
||||
Color::Fixed(226), // bright yellow
|
||||
Color::Fixed(99), // slate blue
|
||||
Color::Fixed(214), // light orange
|
||||
Color::Fixed(48), // spring green
|
||||
Color::Fixed(201), // hot pink
|
||||
Color::Fixed(81), // steel blue
|
||||
Color::Fixed(220), // gold
|
||||
Color::Fixed(105), // medium purple
|
||||
]
|
||||
}
|
||||
fn get_colors() -> &'static [Color] {
|
||||
&[
|
||||
Color::Red,
|
||||
Color::Cyan,
|
||||
Color::Blue,
|
||||
Color::Green,
|
||||
Color::Yellow,
|
||||
Color::Magenta,
|
||||
Color::Fixed(208), // orange
|
||||
Color::Fixed(39), // deep sky blue
|
||||
Color::Fixed(170), // orchid / magenta-pink
|
||||
Color::Fixed(76), // chartreuse
|
||||
Color::Fixed(51), // aqua
|
||||
Color::Fixed(226), // bright yellow
|
||||
Color::Fixed(99), // slate blue
|
||||
Color::Fixed(214), // light orange
|
||||
Color::Fixed(48), // spring green
|
||||
Color::Fixed(201), // hot pink
|
||||
Color::Fixed(81), // steel blue
|
||||
Color::Fixed(220), // gold
|
||||
Color::Fixed(105), // medium purple
|
||||
]
|
||||
}
|
||||
|
||||
pub fn last_color(&mut self) -> Color {
|
||||
if let Some(color) = self.last_color.take() {
|
||||
color
|
||||
} else {
|
||||
let color = self.next().unwrap_or(Color::White);
|
||||
self.last_color = Some(color);
|
||||
color
|
||||
}
|
||||
}
|
||||
pub fn last_color(&mut self) -> Color {
|
||||
if let Some(color) = self.last_color.take() {
|
||||
color
|
||||
} else {
|
||||
let color = self.next().unwrap_or(Color::White);
|
||||
self.last_color = Some(color);
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ColorRng {
|
||||
type Item = Color;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let colors = Self::get_colors();
|
||||
let idx = rand::rngs::SysRng.try_next_u32().ok()? as usize % colors.len();
|
||||
Some(colors[idx])
|
||||
}
|
||||
type Item = Color;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let colors = Self::get_colors();
|
||||
let idx = rand::rngs::SysRng.try_next_u32().ok()? as usize % colors.len();
|
||||
Some(colors[idx])
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static COLOR_RNG: RefCell<ColorRng> = const { RefCell::new(ColorRng { last_color: None }) };
|
||||
static COLOR_RNG: RefCell<ColorRng> = const { RefCell::new(ColorRng { last_color: None }) };
|
||||
}
|
||||
|
||||
pub fn next_color() -> Color {
|
||||
COLOR_RNG.with(|rng| {
|
||||
let color = rng.borrow_mut().next().unwrap();
|
||||
rng.borrow_mut().last_color = Some(color);
|
||||
color
|
||||
})
|
||||
COLOR_RNG.with(|rng| {
|
||||
let color = rng.borrow_mut().next().unwrap();
|
||||
rng.borrow_mut().last_color = Some(color);
|
||||
color
|
||||
})
|
||||
}
|
||||
|
||||
pub fn last_color() -> Color {
|
||||
COLOR_RNG.with(|rng| rng.borrow_mut().last_color())
|
||||
COLOR_RNG.with(|rng| rng.borrow_mut().last_color())
|
||||
}
|
||||
|
||||
pub fn clear_color() {
|
||||
COLOR_RNG.with(|rng| rng.borrow_mut().last_color = None);
|
||||
COLOR_RNG.with(|rng| rng.borrow_mut().last_color = None);
|
||||
}
|
||||
|
||||
pub trait ShResultExt {
|
||||
fn blame(self, span: Span) -> Self;
|
||||
fn try_blame(self, span: Span) -> Self;
|
||||
fn promote_err(self, span: Span) -> Self;
|
||||
fn is_flow_control(&self) -> bool;
|
||||
fn promote_err(self, span: Span) -> Self;
|
||||
fn is_flow_control(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T> ShResultExt for Result<T, ShErr> {
|
||||
/// Blame a span for an error
|
||||
fn blame(self, new_span: Span) -> Self {
|
||||
self.map_err(|e| e.blame(new_span))
|
||||
self.map_err(|e| e.blame(new_span))
|
||||
}
|
||||
/// Blame a span if no blame has been assigned yet
|
||||
fn try_blame(self, new_span: Span) -> Self {
|
||||
self.map_err(|e| e.try_blame(new_span))
|
||||
self.map_err(|e| e.try_blame(new_span))
|
||||
}
|
||||
fn promote_err(self, span: Span) -> Self {
|
||||
self.map_err(|e| e.promote(span))
|
||||
}
|
||||
fn is_flow_control(&self) -> bool {
|
||||
self.as_ref().is_err_and(|e| e.is_flow_control())
|
||||
}
|
||||
fn promote_err(self, span: Span) -> Self {
|
||||
self.map_err(|e| e.promote(span))
|
||||
}
|
||||
fn is_flow_control(&self) -> bool {
|
||||
self.as_ref().is_err_and(|e| e.is_flow_control())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -163,160 +163,256 @@ impl Display for Note {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ShErr {
|
||||
kind: ShErrKind,
|
||||
src_span: Option<Span>,
|
||||
labels: Vec<ariadne::Label<Span>>,
|
||||
sources: Vec<SpanSource>,
|
||||
notes: Vec<String>,
|
||||
kind: ShErrKind,
|
||||
src_span: Option<Span>,
|
||||
labels: Vec<ariadne::Label<Span>>,
|
||||
sources: Vec<SpanSource>,
|
||||
notes: Vec<String>,
|
||||
|
||||
/// If we propagate through a redirect boundary, we take ownership of
|
||||
/// the RedirGuard(s) so that redirections stay alive until the error
|
||||
/// is printed. Multiple guards can accumulate as the error bubbles
|
||||
/// through nested redirect scopes.
|
||||
io_guards: Vec<RedirGuard>
|
||||
/// If we propagate through a redirect boundary, we take ownership of
|
||||
/// the RedirGuard(s) so that redirections stay alive until the error
|
||||
/// is printed. Multiple guards can accumulate as the error bubbles
|
||||
/// through nested redirect scopes.
|
||||
io_guards: Vec<RedirGuard>,
|
||||
}
|
||||
|
||||
impl ShErr {
|
||||
pub fn new(kind: ShErrKind, span: Span) -> Self {
|
||||
Self { kind, src_span: Some(span), labels: vec![], sources: vec![], notes: vec![], io_guards: vec![] }
|
||||
}
|
||||
pub fn simple(kind: ShErrKind, msg: impl Into<String>) -> Self {
|
||||
Self { kind, src_span: None, labels: vec![], sources: vec![], notes: vec![msg.into()], io_guards: vec![] }
|
||||
}
|
||||
pub fn is_flow_control(&self) -> bool {
|
||||
self.kind.is_flow_control()
|
||||
}
|
||||
pub fn promote(mut self, span: Span) -> Self {
|
||||
if self.notes.is_empty() {
|
||||
return self
|
||||
}
|
||||
let first = self.notes[0].clone();
|
||||
if self.notes.len() > 1 {
|
||||
self.notes = self.notes[1..].to_vec();
|
||||
}
|
||||
pub fn new(kind: ShErrKind, span: Span) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
src_span: Some(span),
|
||||
labels: vec![],
|
||||
sources: vec![],
|
||||
notes: vec![],
|
||||
io_guards: vec![],
|
||||
}
|
||||
}
|
||||
pub fn simple(kind: ShErrKind, msg: impl Into<String>) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
src_span: None,
|
||||
labels: vec![],
|
||||
sources: vec![],
|
||||
notes: vec![msg.into()],
|
||||
io_guards: vec![],
|
||||
}
|
||||
}
|
||||
pub fn is_flow_control(&self) -> bool {
|
||||
self.kind.is_flow_control()
|
||||
}
|
||||
pub fn promote(mut self, span: Span) -> Self {
|
||||
if self.notes.is_empty() {
|
||||
return self;
|
||||
}
|
||||
let first = self.notes[0].clone();
|
||||
if self.notes.len() > 1 {
|
||||
self.notes = self.notes[1..].to_vec();
|
||||
}
|
||||
|
||||
self.labeled(span, first)
|
||||
}
|
||||
pub fn with_redirs(mut self, guard: RedirGuard) -> Self {
|
||||
self.io_guards.push(guard);
|
||||
self
|
||||
}
|
||||
pub fn at(kind: ShErrKind, span: Span, msg: impl Into<String>) -> Self {
|
||||
let color = last_color(); // use last_color to ensure the same color is used for the label and the message given
|
||||
let src = span.span_source().clone();
|
||||
let msg: String = msg.into();
|
||||
Self::new(kind, span.clone())
|
||||
.with_label(src, ariadne::Label::new(span).with_color(color).with_message(msg))
|
||||
}
|
||||
pub fn labeled(self, span: Span, msg: impl Into<String>) -> Self {
|
||||
let color = last_color();
|
||||
let src = span.span_source().clone();
|
||||
let msg: String = msg.into();
|
||||
self.with_label(src, ariadne::Label::new(span).with_color(color).with_message(msg))
|
||||
}
|
||||
pub fn blame(self, span: Span) -> Self {
|
||||
let ShErr { kind, src_span: _, labels, sources, notes, io_guards } = self;
|
||||
Self { kind, src_span: Some(span), labels, sources, notes, io_guards }
|
||||
}
|
||||
pub fn try_blame(self, span: Span) -> Self {
|
||||
match self {
|
||||
ShErr { kind, src_span: None, labels, sources, notes, io_guards } => Self { kind, src_span: Some(span), labels, sources, notes, io_guards },
|
||||
_ => self
|
||||
}
|
||||
}
|
||||
pub fn kind(&self) -> &ShErrKind {
|
||||
&self.kind
|
||||
}
|
||||
pub fn rename(mut self, name: impl Into<String>) -> Self {
|
||||
if let Some(span) = self.src_span.as_mut() {
|
||||
span.rename(name.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
pub fn with_label(self, source: SpanSource, label: ariadne::Label<Span>) -> Self {
|
||||
let ShErr { kind, src_span, mut labels, mut sources, notes, io_guards } = self;
|
||||
sources.push(source);
|
||||
labels.push(label);
|
||||
Self { kind, src_span, labels, sources, notes, io_guards }
|
||||
}
|
||||
pub fn with_context(self, ctx: VecDeque<(SpanSource, ariadne::Label<Span>)>) -> Self {
|
||||
let ShErr { kind, src_span, mut labels, mut sources, notes, io_guards } = self;
|
||||
for (src, label) in ctx {
|
||||
sources.push(src);
|
||||
labels.push(label);
|
||||
}
|
||||
Self { kind, src_span, labels, sources, notes, io_guards }
|
||||
}
|
||||
pub fn with_note(self, note: impl Into<String>) -> Self {
|
||||
let ShErr { kind, src_span, labels, sources, mut notes, io_guards } = self;
|
||||
notes.push(note.into());
|
||||
Self { kind, src_span, labels, sources, notes, io_guards }
|
||||
}
|
||||
pub fn build_report(&self) -> Option<Report<'_, Span>> {
|
||||
let span = self.src_span.as_ref()?;
|
||||
let mut report = Report::build(ReportKind::Error, span.clone())
|
||||
.with_config(ariadne::Config::default().with_color(true));
|
||||
let msg = if self.notes.is_empty() {
|
||||
self.kind.to_string()
|
||||
} else {
|
||||
format!("{} - {}", self.kind, self.notes.first().unwrap())
|
||||
};
|
||||
report = report.with_message(msg);
|
||||
self.labeled(span, first)
|
||||
}
|
||||
pub fn with_redirs(mut self, guard: RedirGuard) -> Self {
|
||||
self.io_guards.push(guard);
|
||||
self
|
||||
}
|
||||
pub fn at(kind: ShErrKind, span: Span, msg: impl Into<String>) -> Self {
|
||||
let color = last_color(); // use last_color to ensure the same color is used for the label and the message given
|
||||
let src = span.span_source().clone();
|
||||
let msg: String = msg.into();
|
||||
Self::new(kind, span.clone()).with_label(
|
||||
src,
|
||||
ariadne::Label::new(span)
|
||||
.with_color(color)
|
||||
.with_message(msg),
|
||||
)
|
||||
}
|
||||
pub fn labeled(self, span: Span, msg: impl Into<String>) -> Self {
|
||||
let color = last_color();
|
||||
let src = span.span_source().clone();
|
||||
let msg: String = msg.into();
|
||||
self.with_label(
|
||||
src,
|
||||
ariadne::Label::new(span)
|
||||
.with_color(color)
|
||||
.with_message(msg),
|
||||
)
|
||||
}
|
||||
pub fn blame(self, span: Span) -> Self {
|
||||
let ShErr {
|
||||
kind,
|
||||
src_span: _,
|
||||
labels,
|
||||
sources,
|
||||
notes,
|
||||
io_guards,
|
||||
} = self;
|
||||
Self {
|
||||
kind,
|
||||
src_span: Some(span),
|
||||
labels,
|
||||
sources,
|
||||
notes,
|
||||
io_guards,
|
||||
}
|
||||
}
|
||||
pub fn try_blame(self, span: Span) -> Self {
|
||||
match self {
|
||||
ShErr {
|
||||
kind,
|
||||
src_span: None,
|
||||
labels,
|
||||
sources,
|
||||
notes,
|
||||
io_guards,
|
||||
} => Self {
|
||||
kind,
|
||||
src_span: Some(span),
|
||||
labels,
|
||||
sources,
|
||||
notes,
|
||||
io_guards,
|
||||
},
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
pub fn kind(&self) -> &ShErrKind {
|
||||
&self.kind
|
||||
}
|
||||
pub fn rename(mut self, name: impl Into<String>) -> Self {
|
||||
if let Some(span) = self.src_span.as_mut() {
|
||||
span.rename(name.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
pub fn with_label(self, source: SpanSource, label: ariadne::Label<Span>) -> Self {
|
||||
let ShErr {
|
||||
kind,
|
||||
src_span,
|
||||
mut labels,
|
||||
mut sources,
|
||||
notes,
|
||||
io_guards,
|
||||
} = self;
|
||||
sources.push(source);
|
||||
labels.push(label);
|
||||
Self {
|
||||
kind,
|
||||
src_span,
|
||||
labels,
|
||||
sources,
|
||||
notes,
|
||||
io_guards,
|
||||
}
|
||||
}
|
||||
pub fn with_context(self, ctx: VecDeque<(SpanSource, ariadne::Label<Span>)>) -> Self {
|
||||
let ShErr {
|
||||
kind,
|
||||
src_span,
|
||||
mut labels,
|
||||
mut sources,
|
||||
notes,
|
||||
io_guards,
|
||||
} = self;
|
||||
for (src, label) in ctx {
|
||||
sources.push(src);
|
||||
labels.push(label);
|
||||
}
|
||||
Self {
|
||||
kind,
|
||||
src_span,
|
||||
labels,
|
||||
sources,
|
||||
notes,
|
||||
io_guards,
|
||||
}
|
||||
}
|
||||
pub fn with_note(self, note: impl Into<String>) -> Self {
|
||||
let ShErr {
|
||||
kind,
|
||||
src_span,
|
||||
labels,
|
||||
sources,
|
||||
mut notes,
|
||||
io_guards,
|
||||
} = self;
|
||||
notes.push(note.into());
|
||||
Self {
|
||||
kind,
|
||||
src_span,
|
||||
labels,
|
||||
sources,
|
||||
notes,
|
||||
io_guards,
|
||||
}
|
||||
}
|
||||
pub fn build_report(&self) -> Option<Report<'_, Span>> {
|
||||
let span = self.src_span.as_ref()?;
|
||||
let mut report = Report::build(ReportKind::Error, span.clone())
|
||||
.with_config(ariadne::Config::default().with_color(true));
|
||||
let msg = if self.notes.is_empty() {
|
||||
self.kind.to_string()
|
||||
} else {
|
||||
format!("{} - {}", self.kind, self.notes.first().unwrap())
|
||||
};
|
||||
report = report.with_message(msg);
|
||||
|
||||
for label in self.labels.clone() {
|
||||
report = report.with_label(label);
|
||||
}
|
||||
for note in &self.notes {
|
||||
report = report.with_note(note);
|
||||
}
|
||||
for label in self.labels.clone() {
|
||||
report = report.with_label(label);
|
||||
}
|
||||
for note in &self.notes {
|
||||
report = report.with_note(note);
|
||||
}
|
||||
|
||||
Some(report.finish())
|
||||
}
|
||||
fn collect_sources(&self) -> HashMap<SpanSource, String> {
|
||||
let mut source_map = HashMap::new();
|
||||
if let Some(span) = &self.src_span {
|
||||
let src = span.span_source().clone();
|
||||
source_map.entry(src.clone())
|
||||
.or_insert_with(|| src.content().to_string());
|
||||
}
|
||||
for src in &self.sources {
|
||||
source_map.entry(src.clone())
|
||||
.or_insert_with(|| src.content().to_string());
|
||||
}
|
||||
source_map
|
||||
}
|
||||
pub fn print_error(&self) {
|
||||
let default = || {
|
||||
eprintln!("\n{}", self.kind);
|
||||
for note in &self.notes {
|
||||
eprintln!("note: {note}");
|
||||
}
|
||||
};
|
||||
let Some(report) = self.build_report() else {
|
||||
return default();
|
||||
};
|
||||
Some(report.finish())
|
||||
}
|
||||
fn collect_sources(&self) -> HashMap<SpanSource, String> {
|
||||
let mut source_map = HashMap::new();
|
||||
if let Some(span) = &self.src_span {
|
||||
let src = span.span_source().clone();
|
||||
source_map
|
||||
.entry(src.clone())
|
||||
.or_insert_with(|| src.content().to_string());
|
||||
}
|
||||
for src in &self.sources {
|
||||
source_map
|
||||
.entry(src.clone())
|
||||
.or_insert_with(|| src.content().to_string());
|
||||
}
|
||||
source_map
|
||||
}
|
||||
pub fn print_error(&self) {
|
||||
let default = || {
|
||||
eprintln!("\n{}", self.kind);
|
||||
for note in &self.notes {
|
||||
eprintln!("note: {note}");
|
||||
}
|
||||
};
|
||||
let Some(report) = self.build_report() else {
|
||||
return default();
|
||||
};
|
||||
|
||||
let sources = self.collect_sources();
|
||||
let cache = ariadne::FnCache::new(move |src: &SpanSource| {
|
||||
sources.get(src)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("Failed to fetch source '{}'", src.name()))
|
||||
});
|
||||
eprintln!();
|
||||
if report.eprint(cache).is_err() {
|
||||
default();
|
||||
}
|
||||
}
|
||||
let sources = self.collect_sources();
|
||||
let cache = ariadne::FnCache::new(move |src: &SpanSource| {
|
||||
sources
|
||||
.get(src)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("Failed to fetch source '{}'", src.name()))
|
||||
});
|
||||
eprintln!();
|
||||
if report.eprint(cache).is_err() {
|
||||
default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ShErr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.notes.is_empty() {
|
||||
write!(f, "{}", self.kind)
|
||||
} else {
|
||||
write!(f, "{} - {}", self.kind, self.notes.first().unwrap())
|
||||
}
|
||||
}
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.notes.is_empty() {
|
||||
write!(f, "{}", self.kind)
|
||||
} else {
|
||||
write!(f, "{} - {}", self.kind, self.notes.first().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for ShErr {
|
||||
@@ -350,7 +446,7 @@ pub enum ShErrKind {
|
||||
ResourceLimitExceeded,
|
||||
BadPermission,
|
||||
Errno(Errno),
|
||||
NotFound,
|
||||
NotFound,
|
||||
ReadlineErr,
|
||||
ExCommand,
|
||||
|
||||
@@ -364,15 +460,16 @@ pub enum ShErrKind {
|
||||
}
|
||||
|
||||
impl ShErrKind {
|
||||
pub fn is_flow_control(&self) -> bool {
|
||||
matches!(self,
|
||||
Self::CleanExit(_) |
|
||||
Self::FuncReturn(_) |
|
||||
Self::LoopContinue(_) |
|
||||
Self::LoopBreak(_) |
|
||||
Self::ClearReadline
|
||||
)
|
||||
}
|
||||
pub fn is_flow_control(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::CleanExit(_)
|
||||
| Self::FuncReturn(_)
|
||||
| Self::LoopContinue(_)
|
||||
| Self::LoopBreak(_)
|
||||
| Self::ClearReadline
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ShErrKind {
|
||||
|
||||
@@ -144,7 +144,8 @@ impl RawModeGuard {
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
let current = tcgetattr(borrow_fd(*TTY_FILENO)).expect("Failed to get terminal attributes");
|
||||
let orig = ORIG_TERMIOS.with(|cell| cell.borrow().clone())
|
||||
let orig = ORIG_TERMIOS
|
||||
.with(|cell| cell.borrow().clone())
|
||||
.expect("with_cooked_mode called before raw_mode()");
|
||||
tcsetattr(borrow_fd(*TTY_FILENO), termios::SetArg::TCSANOW, &orig)
|
||||
.expect("Failed to restore cooked mode");
|
||||
|
||||
@@ -25,8 +25,8 @@ pub trait TkVecUtils<Tk> {
|
||||
}
|
||||
|
||||
pub trait AutoCmdVecUtils {
|
||||
fn exec(&self);
|
||||
fn exec_with(&self, pattern: &str);
|
||||
fn exec(&self);
|
||||
fn exec_with(&self, pattern: &str);
|
||||
}
|
||||
|
||||
pub trait RedirVecUtils<Redir> {
|
||||
@@ -37,36 +37,44 @@ pub trait RedirVecUtils<Redir> {
|
||||
}
|
||||
|
||||
pub trait NodeVecUtils<Node> {
|
||||
fn get_span(&self) -> Option<Span>;
|
||||
fn get_span(&self) -> Option<Span>;
|
||||
}
|
||||
|
||||
impl AutoCmdVecUtils for Vec<AutoCmd> {
|
||||
fn exec(&self) {
|
||||
let saved_status = crate::state::get_status();
|
||||
for cmd in self {
|
||||
let AutoCmd { pattern: _, command } = cmd;
|
||||
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd".into())) {
|
||||
e.print_error();
|
||||
}
|
||||
}
|
||||
crate::state::set_status(saved_status);
|
||||
}
|
||||
fn exec_with(&self, other_pattern: &str) {
|
||||
let saved_status = crate::state::get_status();
|
||||
for cmd in self {
|
||||
let AutoCmd { pattern, command } = cmd;
|
||||
if let Some(pat) = pattern
|
||||
&& !pat.is_match(other_pattern) {
|
||||
log::trace!("autocmd pattern '{}' did not match '{}', skipping", pat, other_pattern);
|
||||
continue;
|
||||
}
|
||||
fn exec(&self) {
|
||||
let saved_status = crate::state::get_status();
|
||||
for cmd in self {
|
||||
let AutoCmd {
|
||||
pattern: _,
|
||||
command,
|
||||
} = cmd;
|
||||
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd".into())) {
|
||||
e.print_error();
|
||||
}
|
||||
}
|
||||
crate::state::set_status(saved_status);
|
||||
}
|
||||
fn exec_with(&self, other_pattern: &str) {
|
||||
let saved_status = crate::state::get_status();
|
||||
for cmd in self {
|
||||
let AutoCmd { pattern, command } = cmd;
|
||||
if let Some(pat) = pattern
|
||||
&& !pat.is_match(other_pattern)
|
||||
{
|
||||
log::trace!(
|
||||
"autocmd pattern '{}' did not match '{}', skipping",
|
||||
pat,
|
||||
other_pattern
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd".into())) {
|
||||
e.print_error();
|
||||
}
|
||||
}
|
||||
crate::state::set_status(saved_status);
|
||||
}
|
||||
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd".into())) {
|
||||
e.print_error();
|
||||
}
|
||||
}
|
||||
crate::state::set_status(saved_status);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VecDequeExt<T> for VecDeque<T> {
|
||||
@@ -118,9 +126,12 @@ impl CharDequeUtils for VecDeque<char> {
|
||||
impl TkVecUtils<Tk> for Vec<Tk> {
|
||||
fn get_span(&self) -> Option<Span> {
|
||||
if let Some(first_tk) = self.first() {
|
||||
self
|
||||
.last()
|
||||
.map(|last_tk| Span::new(first_tk.span.range().start..last_tk.span.range().end, first_tk.source()))
|
||||
self.last().map(|last_tk| {
|
||||
Span::new(
|
||||
first_tk.span.range().start..last_tk.span.range().end,
|
||||
first_tk.source(),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -170,13 +181,17 @@ impl RedirVecUtils<Redir> for Vec<Redir> {
|
||||
impl NodeVecUtils<Node> for Vec<Node> {
|
||||
fn get_span(&self) -> Option<Span> {
|
||||
if let Some(first_nd) = self.first()
|
||||
&& let Some(last_nd) = self.last() {
|
||||
let first_start = first_nd.get_span().range().start;
|
||||
let last_end = last_nd.get_span().range().end;
|
||||
if first_start <= last_end {
|
||||
return Some(Span::new(first_start..last_end, first_nd.get_span().source().content()));
|
||||
}
|
||||
&& let Some(last_nd) = self.last()
|
||||
{
|
||||
let first_start = first_nd.get_span().range().start;
|
||||
let last_end = last_nd.get_span().range().end;
|
||||
if first_start <= last_end {
|
||||
return Some(Span::new(
|
||||
first_start..last_end,
|
||||
first_nd.get_span().source().content(),
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user