Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
807 changes: 807 additions & 0 deletions crates/editor-types-macros/src/action.rs

Large diffs are not rendered by default.

847 changes: 32 additions & 815 deletions crates/editor-types-macros/src/lib.rs

Large diffs are not rendered by default.

182 changes: 182 additions & 0 deletions crates/editor-types-macros/src/motion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
use super::*;

impl MotionParser for ActionMacroParser {
type Output = TokenStream;
type Span = Span;

/// Output an error for the current parse.
fn motion_invalid<T: std::fmt::Display>(&self, msg: T, span: Self::Span) -> Self::Output {
ParseError::new(span, msg).to_compile_error()
}

fn visit_buffer_pos(&mut self, position: &[ActionToken], span: Self::Span) -> Self::Output {
let pos = self.parse_move_position(position, span);
quote! { ::editor_types::prelude::MoveType::BufferPos(#pos) }
}

fn visit_buffer_byte_offset(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::MoveType::BufferByteOffset }
}

fn visit_buffer_line_offset(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::MoveType::BufferLineOffset }
}

fn visit_buffer_line_percent(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::MoveType::BufferLinePercent }
}

fn visit_column(
&mut self,
dir: &[ActionToken],
multiline: &[ActionToken],
span: Self::Span,
) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
let multiline = self.parse_bool(multiline, span);
quote! { ::editor_types::prelude::MoveType::Column(#dir, #multiline) }
}

fn visit_final_non_blank(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::FinalNonBlank(#dir) }
}

fn visit_first_word(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::FirstWord(#dir) }
}

fn visit_item_match(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::MoveType::ItemMatch }
}

fn visit_line(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::Line(#dir) }
}

fn visit_line_column_offset(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::MoveType::LineColumnOffset }
}

fn visit_line_percent(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::MoveType::LinePercent }
}

fn visit_line_pos(&mut self, position: &[ActionToken], span: Self::Span) -> Self::Output {
let pos = self.parse_move_position(position, span);
quote! { ::editor_types::prelude::MoveType::LinePos(#pos) }
}

fn visit_word_begin(
&mut self,
style: &[ActionToken],
dir: &[ActionToken],
span: Self::Span,
) -> Self::Output {
let style = self.parse_word_style(style, span);
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::WordBegin(#style, #dir) }
}

fn visit_word_end(
&mut self,
style: &[ActionToken],
dir: &[ActionToken],
span: Self::Span,
) -> Self::Output {
let style = self.parse_word_style(style, span);
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::WordEnd(#style, #dir) }
}

fn visit_paragraph_begin(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::ParagraphBegin(#dir) }
}

fn visit_sentence_begin(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::SentenceBegin(#dir) }
}

fn visit_section_begin(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::SectionBegin(#dir) }
}

fn visit_section_end(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::SectionEnd(#dir) }
}

fn visit_screen_first_word(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::ScreenFirstWord(#dir) }
}

fn visit_screen_line(&mut self, dir: &[ActionToken], span: Self::Span) -> Self::Output {
let dir = self.parse_dir1d(dir, span);
quote! { ::editor_types::prelude::MoveType::ScreenLine(#dir) }
}

fn visit_screen_line_pos(
&mut self,
position: &[ActionToken],
span: Self::Span,
) -> Self::Output {
let pos = self.parse_move_position(position, span);
quote! { ::editor_types::prelude::MoveType::ScreenLinePos(#pos) }
}

fn visit_viewport_pos(&mut self, position: &[ActionToken], span: Self::Span) -> Self::Output {
let pos = self.parse_move_position(position, span);
quote! { ::editor_types::prelude::MoveType::ViewportPos(#pos) }
}
}

pub struct MotionMacroInput {
args: Vec<(Ident, Expr)>,
acts: TokenStream,
}

impl MotionMacroInput {
pub fn into_stream(self) -> TokenStream {
let mut act = TokenStream::new();

for (ident, expr) in self.args {
act.extend(quote! { let #ident = { #expr }; });
}

act.extend(self.acts);
quote! { { #act } }
}
}

impl Parse for MotionMacroInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let fmt = input.parse::<LitStr>()?;
let fmt_str = fmt.value();
let tokens = tokenize(&fmt_str).expect("Motion expression should be valid");
let arg_exprs = if input.parse::<Token![,]>().is_ok() {
Punctuated::<Expr, Token![,]>::parse_separated_nonempty(input)?
} else {
Punctuated::new()
};
let mut idents = vec![];
let mut args = vec![];

for (i, arg) in arg_exprs.into_iter().enumerate() {
let ident = format_ident!("arg{i}");
idents.push(ident.clone());
args.push((ident, arg));
}

let mut parser = ActionMacroParser { params: idents, pos: 0 };
let acts = parser.parse_motion(tokens.as_slice(), fmt.span());
let generator = Self { args, acts };

Ok(generator)
}
}
100 changes: 100 additions & 0 deletions crates/editor-types-macros/src/range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use super::*;

impl RangeParser for ActionMacroParser {
type Output = TokenStream;
type Span = Span;

fn range_invalid<T: std::fmt::Display>(&self, msg: T, span: Self::Span) -> Self::Output {
ParseError::new(span, msg).to_compile_error()
}

fn visit_word(&mut self, style: &[ActionToken], span: Self::Span) -> Self::Output {
let style = self.parse_word_style(style, span);
quote! { ::editor_types::prelude::RangeType::Word(#style) }
}

fn visit_buffer(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::RangeType::Buffer }
}

fn visit_paragraph(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::RangeType::Paragraph }
}

fn visit_sentence(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::RangeType::Sentence }
}

fn visit_line(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::RangeType::Line }
}

fn visit_bracketed(
&mut self,
left: &[ActionToken],
right: &[ActionToken],
span: Self::Span,
) -> Self::Output {
let left = self.parse_std_char(left, span);
let right = self.parse_std_char(right, span);
quote! { ::editor_types::prelude::RangeType::Bracketed(#left, #right) }
}

fn visit_item(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::RangeType::Item }
}

fn visit_quote(&mut self, surround: &[ActionToken], span: Self::Span) -> Self::Output {
let c = self.parse_std_char(surround, span);
quote! { ::editor_types::prelude::RangeType::Quote(#c) }
}

fn visit_xml_tag(&mut self, _: Self::Span) -> Self::Output {
quote! { ::editor_types::prelude::RangeType::XmlTag }
}
}

pub struct RangeMacroInput {
args: Vec<(Ident, Expr)>,
acts: TokenStream,
}

impl RangeMacroInput {
pub fn into_stream(self) -> TokenStream {
let mut act = TokenStream::new();

for (ident, expr) in self.args {
act.extend(quote! { let #ident = { #expr }; });
}

act.extend(self.acts);
quote! { { #act } }
}
}

impl Parse for RangeMacroInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let fmt = input.parse::<LitStr>()?;
let fmt_str = fmt.value();
let tokens = tokenize(&fmt_str).expect("Range expression should be valid");
let arg_exprs = if input.parse::<Token![,]>().is_ok() {
Punctuated::<Expr, Token![,]>::parse_separated_nonempty(input)?
} else {
Punctuated::new()
};
let mut idents = vec![];
let mut args = vec![];

for (i, arg) in arg_exprs.into_iter().enumerate() {
let ident = format_ident!("arg{i}");
idents.push(ident.clone());
args.push((ident, arg));
}

let mut parser = ActionMacroParser { params: idents, pos: 0 };
let acts = parser.parse_range(tokens.as_slice(), fmt.span());
let generator = Self { args, acts };

Ok(generator)
}
}
Loading
Loading