Rename Magic* to IpyEscape* (#6395)

## Summary

This PR renames the `MagicCommand` token to `IpyEscapeCommand` token and
`MagicKind` to `IpyEscapeKind` type to better reflect the purpose of the
token and type. Similarly, it renames the AST nodes from `LineMagic` to
`IpyEscapeCommand` prefixed with `Stmt`/`Expr` wherever necessary.

It also makes renames from using `jupyter_magic` to
`ipython_escape_commands` in various function names.

The mode value is still `Mode::Jupyter` because the escape commands are
part of the IPython syntax but the lexing/parsing is done for a Jupyter
notebook.

### Motivation behind the rename:
* IPython codebase defines it as "EscapeCommand" / "Escape Sequences":
* Escape Sequences:
292e3a2345/IPython/core/inputtransformer2.py (L329-L333)
* Escape command:
292e3a2345/IPython/core/inputtransformer2.py (L410-L411)
* The word "magic" is used mainly for the actual magic commands i.e.,
the ones starting with `%`/`%%`
(https://ipython.readthedocs.io/en/stable/interactive/reference.html#magic-command-system).
So, this avoids any confusion between the Magic token (`%`, `%%`) and
the escape command itself.
## Test Plan

* `cargo test` to make sure all renames are done correctly.
* `grep` for `jupyter_escape`/`magic` to make sure all renames are done
correctly.
This commit is contained in:
Dhruv Manilawala 2023-08-09 18:58:18 +05:30 committed by GitHub
parent 3bf1c66cda
commit 6a64f2289b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 949 additions and 946 deletions

View file

@ -571,11 +571,11 @@ print("after empty cells")
} }
#[test] #[test]
fn test_line_magics() -> Result<()> { fn test_ipy_escape_command() -> Result<()> {
let path = "line_magics.ipynb".to_string(); let path = "ipy_escape_command.ipynb".to_string();
let (diagnostics, source_kind, _) = test_notebook_path( let (diagnostics, source_kind, _) = test_notebook_path(
&path, &path,
Path::new("line_magics_expected.ipynb"), Path::new("ipy_escape_command_expected.ipynb"),
&settings::Settings::for_rule(Rule::UnusedImport), &settings::Settings::for_rule(Rule::UnusedImport),
)?; )?;
assert_messages!(diagnostics, path, source_kind); assert_messages!(diagnostics, path, source_kind);

View file

@ -1,7 +1,7 @@
--- ---
source: crates/ruff/src/jupyter/notebook.rs source: crates/ruff/src/jupyter/notebook.rs
--- ---
line_magics.ipynb:cell 1:5:8: F401 [*] `os` imported but unused ipy_escape_command.ipynb:cell 1:5:8: F401 [*] `os` imported but unused
| |
3 | %matplotlib inline 3 | %matplotlib inline
4 | 4 |

View file

@ -653,13 +653,13 @@ impl<'stmt> BasicBlocksBuilder<'stmt> {
| Expr::Await(_) | Expr::Await(_)
| Expr::Yield(_) | Expr::Yield(_)
| Expr::YieldFrom(_) => self.unconditional_next_block(after), | Expr::YieldFrom(_) => self.unconditional_next_block(after),
Expr::LineMagic(_) => todo!(), Expr::IpyEscapeCommand(_) => todo!(),
} }
} }
// The tough branches are done, here is an easy one. // The tough branches are done, here is an easy one.
Stmt::Return(_) => NextBlock::Terminate, Stmt::Return(_) => NextBlock::Terminate,
Stmt::TypeAlias(_) => todo!(), Stmt::TypeAlias(_) => todo!(),
Stmt::LineMagic(_) => todo!(), Stmt::IpyEscapeCommand(_) => todo!(),
}; };
// Include any statements in the block that don't divert the control flow. // Include any statements in the block that don't divert the control flow.
@ -903,7 +903,7 @@ fn needs_next_block(stmts: &[Stmt]) -> bool {
| Stmt::TryStar(_) | Stmt::TryStar(_)
| Stmt::Assert(_) => true, | Stmt::Assert(_) => true,
Stmt::TypeAlias(_) => todo!(), Stmt::TypeAlias(_) => todo!(),
Stmt::LineMagic(_) => todo!(), Stmt::IpyEscapeCommand(_) => todo!(),
} }
} }
@ -936,7 +936,7 @@ fn is_control_flow_stmt(stmt: &Stmt) -> bool {
| Stmt::Break(_) | Stmt::Break(_)
| Stmt::Continue(_) => true, | Stmt::Continue(_) => true,
Stmt::TypeAlias(_) => todo!(), Stmt::TypeAlias(_) => todo!(),
Stmt::LineMagic(_) => todo!(), Stmt::IpyEscapeCommand(_) => todo!(),
} }
} }

View file

@ -672,8 +672,8 @@ pub struct ExprSlice<'a> {
} }
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprLineMagic<'a> { pub struct ExprIpyEscapeCommand<'a> {
kind: ast::MagicKind, kind: ast::IpyEscapeKind,
value: &'a str, value: &'a str,
} }
@ -706,7 +706,7 @@ pub enum ComparableExpr<'a> {
List(ExprList<'a>), List(ExprList<'a>),
Tuple(ExprTuple<'a>), Tuple(ExprTuple<'a>),
Slice(ExprSlice<'a>), Slice(ExprSlice<'a>),
LineMagic(ExprLineMagic<'a>), IpyEscapeCommand(ExprIpyEscapeCommand<'a>),
} }
impl<'a> From<&'a Box<ast::Expr>> for Box<ComparableExpr<'a>> { impl<'a> From<&'a Box<ast::Expr>> for Box<ComparableExpr<'a>> {
@ -936,11 +936,11 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
upper: upper.as_ref().map(Into::into), upper: upper.as_ref().map(Into::into),
step: step.as_ref().map(Into::into), step: step.as_ref().map(Into::into),
}), }),
ast::Expr::LineMagic(ast::ExprLineMagic { ast::Expr::IpyEscapeCommand(ast::ExprIpyEscapeCommand {
kind, kind,
value, value,
range: _, range: _,
}) => Self::LineMagic(ExprLineMagic { }) => Self::IpyEscapeCommand(ExprIpyEscapeCommand {
kind: *kind, kind: *kind,
value: value.as_str(), value: value.as_str(),
}), }),
@ -1165,8 +1165,8 @@ pub struct StmtExpr<'a> {
} }
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
pub struct StmtLineMagic<'a> { pub struct StmtIpyEscapeCommand<'a> {
kind: ast::MagicKind, kind: ast::IpyEscapeKind,
value: &'a str, value: &'a str,
} }
@ -1193,7 +1193,7 @@ pub enum ComparableStmt<'a> {
ImportFrom(StmtImportFrom<'a>), ImportFrom(StmtImportFrom<'a>),
Global(StmtGlobal<'a>), Global(StmtGlobal<'a>),
Nonlocal(StmtNonlocal<'a>), Nonlocal(StmtNonlocal<'a>),
LineMagic(StmtLineMagic<'a>), IpyEscapeCommand(StmtIpyEscapeCommand<'a>),
Expr(StmtExpr<'a>), Expr(StmtExpr<'a>),
Pass, Pass,
Break, Break,
@ -1394,11 +1394,11 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
names: names.iter().map(ast::Identifier::as_str).collect(), names: names.iter().map(ast::Identifier::as_str).collect(),
}) })
} }
ast::Stmt::LineMagic(ast::StmtLineMagic { ast::Stmt::IpyEscapeCommand(ast::StmtIpyEscapeCommand {
kind, kind,
value, value,
range: _, range: _,
}) => Self::LineMagic(StmtLineMagic { }) => Self::IpyEscapeCommand(StmtIpyEscapeCommand {
kind: *kind, kind: *kind,
value: value.as_str(), value: value.as_str(),
}), }),

View file

@ -108,7 +108,7 @@ where
| Expr::Subscript(_) | Expr::Subscript(_)
| Expr::Yield(_) | Expr::Yield(_)
| Expr::YieldFrom(_) | Expr::YieldFrom(_)
| Expr::LineMagic(_) | Expr::IpyEscapeCommand(_)
) )
}) })
} }
@ -247,7 +247,7 @@ where
.is_some_and(|value| any_over_expr(value, func)) .is_some_and(|value| any_over_expr(value, func))
} }
Expr::Name(_) | Expr::Constant(_) => false, Expr::Name(_) | Expr::Constant(_) => false,
Expr::LineMagic(_) => false, Expr::IpyEscapeCommand(_) => false,
} }
} }
@ -534,7 +534,7 @@ where
Stmt::Nonlocal(_) => false, Stmt::Nonlocal(_) => false,
Stmt::Expr(ast::StmtExpr { value, range: _ }) => any_over_expr(value, func), Stmt::Expr(ast::StmtExpr { value, range: _ }) => any_over_expr(value, func),
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) => false, Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) => false,
Stmt::LineMagic(_) => false, Stmt::IpyEscapeCommand(_) => false,
} }
} }

View file

@ -48,7 +48,7 @@ pub enum AnyNode {
StmtPass(ast::StmtPass), StmtPass(ast::StmtPass),
StmtBreak(ast::StmtBreak), StmtBreak(ast::StmtBreak),
StmtContinue(ast::StmtContinue), StmtContinue(ast::StmtContinue),
StmtLineMagic(ast::StmtLineMagic), StmtIpyEscapeCommand(ast::StmtIpyEscapeCommand),
ExprBoolOp(ast::ExprBoolOp), ExprBoolOp(ast::ExprBoolOp),
ExprNamedExpr(ast::ExprNamedExpr), ExprNamedExpr(ast::ExprNamedExpr),
ExprBinOp(ast::ExprBinOp), ExprBinOp(ast::ExprBinOp),
@ -76,7 +76,7 @@ pub enum AnyNode {
ExprList(ast::ExprList), ExprList(ast::ExprList),
ExprTuple(ast::ExprTuple), ExprTuple(ast::ExprTuple),
ExprSlice(ast::ExprSlice), ExprSlice(ast::ExprSlice),
ExprLineMagic(ast::ExprLineMagic), ExprIpyEscapeCommand(ast::ExprIpyEscapeCommand),
ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler), ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler),
PatternMatchValue(ast::PatternMatchValue), PatternMatchValue(ast::PatternMatchValue),
PatternMatchSingleton(ast::PatternMatchSingleton), PatternMatchSingleton(ast::PatternMatchSingleton),
@ -131,7 +131,7 @@ impl AnyNode {
AnyNode::StmtPass(node) => Some(Stmt::Pass(node)), AnyNode::StmtPass(node) => Some(Stmt::Pass(node)),
AnyNode::StmtBreak(node) => Some(Stmt::Break(node)), AnyNode::StmtBreak(node) => Some(Stmt::Break(node)),
AnyNode::StmtContinue(node) => Some(Stmt::Continue(node)), AnyNode::StmtContinue(node) => Some(Stmt::Continue(node)),
AnyNode::StmtLineMagic(node) => Some(Stmt::LineMagic(node)), AnyNode::StmtIpyEscapeCommand(node) => Some(Stmt::IpyEscapeCommand(node)),
AnyNode::ModModule(_) AnyNode::ModModule(_)
| AnyNode::ModExpression(_) | AnyNode::ModExpression(_)
@ -162,7 +162,7 @@ impl AnyNode {
| AnyNode::ExprList(_) | AnyNode::ExprList(_)
| AnyNode::ExprTuple(_) | AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_) | AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_) | AnyNode::ExprIpyEscapeCommand(_)
| AnyNode::ExceptHandlerExceptHandler(_) | AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSingleton(_)
@ -219,7 +219,7 @@ impl AnyNode {
AnyNode::ExprList(node) => Some(Expr::List(node)), AnyNode::ExprList(node) => Some(Expr::List(node)),
AnyNode::ExprTuple(node) => Some(Expr::Tuple(node)), AnyNode::ExprTuple(node) => Some(Expr::Tuple(node)),
AnyNode::ExprSlice(node) => Some(Expr::Slice(node)), AnyNode::ExprSlice(node) => Some(Expr::Slice(node)),
AnyNode::ExprLineMagic(node) => Some(Expr::LineMagic(node)), AnyNode::ExprIpyEscapeCommand(node) => Some(Expr::IpyEscapeCommand(node)),
AnyNode::ModModule(_) AnyNode::ModModule(_)
| AnyNode::ModExpression(_) | AnyNode::ModExpression(_)
@ -248,7 +248,7 @@ impl AnyNode {
| AnyNode::StmtPass(_) | AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_) | AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_) | AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_) | AnyNode::StmtIpyEscapeCommand(_)
| AnyNode::ExceptHandlerExceptHandler(_) | AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSingleton(_)
@ -306,7 +306,7 @@ impl AnyNode {
| AnyNode::StmtPass(_) | AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_) | AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_) | AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_) | AnyNode::StmtIpyEscapeCommand(_)
| AnyNode::ExprBoolOp(_) | AnyNode::ExprBoolOp(_)
| AnyNode::ExprNamedExpr(_) | AnyNode::ExprNamedExpr(_)
| AnyNode::ExprBinOp(_) | AnyNode::ExprBinOp(_)
@ -334,7 +334,7 @@ impl AnyNode {
| AnyNode::ExprList(_) | AnyNode::ExprList(_)
| AnyNode::ExprTuple(_) | AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_) | AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_) | AnyNode::ExprIpyEscapeCommand(_)
| AnyNode::ExceptHandlerExceptHandler(_) | AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSingleton(_)
@ -400,7 +400,7 @@ impl AnyNode {
| AnyNode::StmtPass(_) | AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_) | AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_) | AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_) | AnyNode::StmtIpyEscapeCommand(_)
| AnyNode::ExprBoolOp(_) | AnyNode::ExprBoolOp(_)
| AnyNode::ExprNamedExpr(_) | AnyNode::ExprNamedExpr(_)
| AnyNode::ExprBinOp(_) | AnyNode::ExprBinOp(_)
@ -428,7 +428,7 @@ impl AnyNode {
| AnyNode::ExprList(_) | AnyNode::ExprList(_)
| AnyNode::ExprTuple(_) | AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_) | AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_) | AnyNode::ExprIpyEscapeCommand(_)
| AnyNode::ExceptHandlerExceptHandler(_) | AnyNode::ExceptHandlerExceptHandler(_)
| AnyNode::Comprehension(_) | AnyNode::Comprehension(_)
| AnyNode::Arguments(_) | AnyNode::Arguments(_)
@ -479,7 +479,7 @@ impl AnyNode {
| AnyNode::StmtPass(_) | AnyNode::StmtPass(_)
| AnyNode::StmtBreak(_) | AnyNode::StmtBreak(_)
| AnyNode::StmtContinue(_) | AnyNode::StmtContinue(_)
| AnyNode::StmtLineMagic(_) | AnyNode::StmtIpyEscapeCommand(_)
| AnyNode::ExprBoolOp(_) | AnyNode::ExprBoolOp(_)
| AnyNode::ExprNamedExpr(_) | AnyNode::ExprNamedExpr(_)
| AnyNode::ExprBinOp(_) | AnyNode::ExprBinOp(_)
@ -507,7 +507,7 @@ impl AnyNode {
| AnyNode::ExprList(_) | AnyNode::ExprList(_)
| AnyNode::ExprTuple(_) | AnyNode::ExprTuple(_)
| AnyNode::ExprSlice(_) | AnyNode::ExprSlice(_)
| AnyNode::ExprLineMagic(_) | AnyNode::ExprIpyEscapeCommand(_)
| AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchValue(_)
| AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSingleton(_)
| AnyNode::PatternMatchSequence(_) | AnyNode::PatternMatchSequence(_)
@ -583,7 +583,7 @@ impl AnyNode {
Self::StmtPass(node) => AnyNodeRef::StmtPass(node), Self::StmtPass(node) => AnyNodeRef::StmtPass(node),
Self::StmtBreak(node) => AnyNodeRef::StmtBreak(node), Self::StmtBreak(node) => AnyNodeRef::StmtBreak(node),
Self::StmtContinue(node) => AnyNodeRef::StmtContinue(node), Self::StmtContinue(node) => AnyNodeRef::StmtContinue(node),
Self::StmtLineMagic(node) => AnyNodeRef::StmtLineMagic(node), Self::StmtIpyEscapeCommand(node) => AnyNodeRef::StmtIpyEscapeCommand(node),
Self::ExprBoolOp(node) => AnyNodeRef::ExprBoolOp(node), Self::ExprBoolOp(node) => AnyNodeRef::ExprBoolOp(node),
Self::ExprNamedExpr(node) => AnyNodeRef::ExprNamedExpr(node), Self::ExprNamedExpr(node) => AnyNodeRef::ExprNamedExpr(node),
Self::ExprBinOp(node) => AnyNodeRef::ExprBinOp(node), Self::ExprBinOp(node) => AnyNodeRef::ExprBinOp(node),
@ -611,7 +611,7 @@ impl AnyNode {
Self::ExprList(node) => AnyNodeRef::ExprList(node), Self::ExprList(node) => AnyNodeRef::ExprList(node),
Self::ExprTuple(node) => AnyNodeRef::ExprTuple(node), Self::ExprTuple(node) => AnyNodeRef::ExprTuple(node),
Self::ExprSlice(node) => AnyNodeRef::ExprSlice(node), Self::ExprSlice(node) => AnyNodeRef::ExprSlice(node),
Self::ExprLineMagic(node) => AnyNodeRef::ExprLineMagic(node), Self::ExprIpyEscapeCommand(node) => AnyNodeRef::ExprIpyEscapeCommand(node),
Self::ExceptHandlerExceptHandler(node) => AnyNodeRef::ExceptHandlerExceptHandler(node), Self::ExceptHandlerExceptHandler(node) => AnyNodeRef::ExceptHandlerExceptHandler(node),
Self::PatternMatchValue(node) => AnyNodeRef::PatternMatchValue(node), Self::PatternMatchValue(node) => AnyNodeRef::PatternMatchValue(node),
Self::PatternMatchSingleton(node) => AnyNodeRef::PatternMatchSingleton(node), Self::PatternMatchSingleton(node) => AnyNodeRef::PatternMatchSingleton(node),
@ -1429,12 +1429,12 @@ impl AstNode for ast::StmtContinue {
AnyNode::from(self) AnyNode::from(self)
} }
} }
impl AstNode for ast::StmtLineMagic { impl AstNode for ast::StmtIpyEscapeCommand {
fn cast(kind: AnyNode) -> Option<Self> fn cast(kind: AnyNode) -> Option<Self>
where where
Self: Sized, Self: Sized,
{ {
if let AnyNode::StmtLineMagic(node) = kind { if let AnyNode::StmtIpyEscapeCommand(node) = kind {
Some(node) Some(node)
} else { } else {
None None
@ -1442,7 +1442,7 @@ impl AstNode for ast::StmtLineMagic {
} }
fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { fn cast_ref(kind: AnyNodeRef) -> Option<&Self> {
if let AnyNodeRef::StmtLineMagic(node) = kind { if let AnyNodeRef::StmtIpyEscapeCommand(node) = kind {
Some(node) Some(node)
} else { } else {
None None
@ -2213,12 +2213,12 @@ impl AstNode for ast::ExprSlice {
AnyNode::from(self) AnyNode::from(self)
} }
} }
impl AstNode for ast::ExprLineMagic { impl AstNode for ast::ExprIpyEscapeCommand {
fn cast(kind: AnyNode) -> Option<Self> fn cast(kind: AnyNode) -> Option<Self>
where where
Self: Sized, Self: Sized,
{ {
if let AnyNode::ExprLineMagic(node) = kind { if let AnyNode::ExprIpyEscapeCommand(node) = kind {
Some(node) Some(node)
} else { } else {
None None
@ -2226,7 +2226,7 @@ impl AstNode for ast::ExprLineMagic {
} }
fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { fn cast_ref(kind: AnyNodeRef) -> Option<&Self> {
if let AnyNodeRef::ExprLineMagic(node) = kind { if let AnyNodeRef::ExprIpyEscapeCommand(node) = kind {
Some(node) Some(node)
} else { } else {
None None
@ -2915,7 +2915,7 @@ impl From<Stmt> for AnyNode {
Stmt::Pass(node) => AnyNode::StmtPass(node), Stmt::Pass(node) => AnyNode::StmtPass(node),
Stmt::Break(node) => AnyNode::StmtBreak(node), Stmt::Break(node) => AnyNode::StmtBreak(node),
Stmt::Continue(node) => AnyNode::StmtContinue(node), Stmt::Continue(node) => AnyNode::StmtContinue(node),
Stmt::LineMagic(node) => AnyNode::StmtLineMagic(node), Stmt::IpyEscapeCommand(node) => AnyNode::StmtIpyEscapeCommand(node),
} }
} }
} }
@ -2950,7 +2950,7 @@ impl From<Expr> for AnyNode {
Expr::List(node) => AnyNode::ExprList(node), Expr::List(node) => AnyNode::ExprList(node),
Expr::Tuple(node) => AnyNode::ExprTuple(node), Expr::Tuple(node) => AnyNode::ExprTuple(node),
Expr::Slice(node) => AnyNode::ExprSlice(node), Expr::Slice(node) => AnyNode::ExprSlice(node),
Expr::LineMagic(node) => AnyNode::ExprLineMagic(node), Expr::IpyEscapeCommand(node) => AnyNode::ExprIpyEscapeCommand(node),
} }
} }
} }
@ -3155,9 +3155,9 @@ impl From<ast::StmtContinue> for AnyNode {
} }
} }
impl From<ast::StmtLineMagic> for AnyNode { impl From<ast::StmtIpyEscapeCommand> for AnyNode {
fn from(node: ast::StmtLineMagic) -> Self { fn from(node: ast::StmtIpyEscapeCommand) -> Self {
AnyNode::StmtLineMagic(node) AnyNode::StmtIpyEscapeCommand(node)
} }
} }
@ -3323,9 +3323,9 @@ impl From<ast::ExprSlice> for AnyNode {
} }
} }
impl From<ast::ExprLineMagic> for AnyNode { impl From<ast::ExprIpyEscapeCommand> for AnyNode {
fn from(node: ast::ExprLineMagic) -> Self { fn from(node: ast::ExprIpyEscapeCommand) -> Self {
AnyNode::ExprLineMagic(node) AnyNode::ExprIpyEscapeCommand(node)
} }
} }
@ -3486,7 +3486,7 @@ impl Ranged for AnyNode {
AnyNode::StmtPass(node) => node.range(), AnyNode::StmtPass(node) => node.range(),
AnyNode::StmtBreak(node) => node.range(), AnyNode::StmtBreak(node) => node.range(),
AnyNode::StmtContinue(node) => node.range(), AnyNode::StmtContinue(node) => node.range(),
AnyNode::StmtLineMagic(node) => node.range(), AnyNode::StmtIpyEscapeCommand(node) => node.range(),
AnyNode::ExprBoolOp(node) => node.range(), AnyNode::ExprBoolOp(node) => node.range(),
AnyNode::ExprNamedExpr(node) => node.range(), AnyNode::ExprNamedExpr(node) => node.range(),
AnyNode::ExprBinOp(node) => node.range(), AnyNode::ExprBinOp(node) => node.range(),
@ -3514,7 +3514,7 @@ impl Ranged for AnyNode {
AnyNode::ExprList(node) => node.range(), AnyNode::ExprList(node) => node.range(),
AnyNode::ExprTuple(node) => node.range(), AnyNode::ExprTuple(node) => node.range(),
AnyNode::ExprSlice(node) => node.range(), AnyNode::ExprSlice(node) => node.range(),
AnyNode::ExprLineMagic(node) => node.range(), AnyNode::ExprIpyEscapeCommand(node) => node.range(),
AnyNode::ExceptHandlerExceptHandler(node) => node.range(), AnyNode::ExceptHandlerExceptHandler(node) => node.range(),
AnyNode::PatternMatchValue(node) => node.range(), AnyNode::PatternMatchValue(node) => node.range(),
AnyNode::PatternMatchSingleton(node) => node.range(), AnyNode::PatternMatchSingleton(node) => node.range(),
@ -3572,7 +3572,7 @@ pub enum AnyNodeRef<'a> {
StmtPass(&'a ast::StmtPass), StmtPass(&'a ast::StmtPass),
StmtBreak(&'a ast::StmtBreak), StmtBreak(&'a ast::StmtBreak),
StmtContinue(&'a ast::StmtContinue), StmtContinue(&'a ast::StmtContinue),
StmtLineMagic(&'a ast::StmtLineMagic), StmtIpyEscapeCommand(&'a ast::StmtIpyEscapeCommand),
ExprBoolOp(&'a ast::ExprBoolOp), ExprBoolOp(&'a ast::ExprBoolOp),
ExprNamedExpr(&'a ast::ExprNamedExpr), ExprNamedExpr(&'a ast::ExprNamedExpr),
ExprBinOp(&'a ast::ExprBinOp), ExprBinOp(&'a ast::ExprBinOp),
@ -3600,7 +3600,7 @@ pub enum AnyNodeRef<'a> {
ExprList(&'a ast::ExprList), ExprList(&'a ast::ExprList),
ExprTuple(&'a ast::ExprTuple), ExprTuple(&'a ast::ExprTuple),
ExprSlice(&'a ast::ExprSlice), ExprSlice(&'a ast::ExprSlice),
ExprLineMagic(&'a ast::ExprLineMagic), ExprIpyEscapeCommand(&'a ast::ExprIpyEscapeCommand),
ExceptHandlerExceptHandler(&'a ast::ExceptHandlerExceptHandler), ExceptHandlerExceptHandler(&'a ast::ExceptHandlerExceptHandler),
PatternMatchValue(&'a ast::PatternMatchValue), PatternMatchValue(&'a ast::PatternMatchValue),
PatternMatchSingleton(&'a ast::PatternMatchSingleton), PatternMatchSingleton(&'a ast::PatternMatchSingleton),
@ -3657,7 +3657,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::StmtPass(node) => NonNull::from(*node).cast(), AnyNodeRef::StmtPass(node) => NonNull::from(*node).cast(),
AnyNodeRef::StmtBreak(node) => NonNull::from(*node).cast(), AnyNodeRef::StmtBreak(node) => NonNull::from(*node).cast(),
AnyNodeRef::StmtContinue(node) => NonNull::from(*node).cast(), AnyNodeRef::StmtContinue(node) => NonNull::from(*node).cast(),
AnyNodeRef::StmtLineMagic(node) => NonNull::from(*node).cast(), AnyNodeRef::StmtIpyEscapeCommand(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprBoolOp(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprBoolOp(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprNamedExpr(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprNamedExpr(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprBinOp(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprBinOp(node) => NonNull::from(*node).cast(),
@ -3685,7 +3685,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::ExprList(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprList(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprTuple(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprTuple(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprSlice(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprSlice(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExprLineMagic(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprIpyEscapeCommand(node) => NonNull::from(*node).cast(),
AnyNodeRef::ExceptHandlerExceptHandler(node) => NonNull::from(*node).cast(), AnyNodeRef::ExceptHandlerExceptHandler(node) => NonNull::from(*node).cast(),
AnyNodeRef::PatternMatchValue(node) => NonNull::from(*node).cast(), AnyNodeRef::PatternMatchValue(node) => NonNull::from(*node).cast(),
AnyNodeRef::PatternMatchSingleton(node) => NonNull::from(*node).cast(), AnyNodeRef::PatternMatchSingleton(node) => NonNull::from(*node).cast(),
@ -3748,7 +3748,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::StmtPass(_) => NodeKind::StmtPass, AnyNodeRef::StmtPass(_) => NodeKind::StmtPass,
AnyNodeRef::StmtBreak(_) => NodeKind::StmtBreak, AnyNodeRef::StmtBreak(_) => NodeKind::StmtBreak,
AnyNodeRef::StmtContinue(_) => NodeKind::StmtContinue, AnyNodeRef::StmtContinue(_) => NodeKind::StmtContinue,
AnyNodeRef::StmtLineMagic(_) => NodeKind::StmtLineMagic, AnyNodeRef::StmtIpyEscapeCommand(_) => NodeKind::StmtIpyEscapeCommand,
AnyNodeRef::ExprBoolOp(_) => NodeKind::ExprBoolOp, AnyNodeRef::ExprBoolOp(_) => NodeKind::ExprBoolOp,
AnyNodeRef::ExprNamedExpr(_) => NodeKind::ExprNamedExpr, AnyNodeRef::ExprNamedExpr(_) => NodeKind::ExprNamedExpr,
AnyNodeRef::ExprBinOp(_) => NodeKind::ExprBinOp, AnyNodeRef::ExprBinOp(_) => NodeKind::ExprBinOp,
@ -3776,7 +3776,7 @@ impl AnyNodeRef<'_> {
AnyNodeRef::ExprList(_) => NodeKind::ExprList, AnyNodeRef::ExprList(_) => NodeKind::ExprList,
AnyNodeRef::ExprTuple(_) => NodeKind::ExprTuple, AnyNodeRef::ExprTuple(_) => NodeKind::ExprTuple,
AnyNodeRef::ExprSlice(_) => NodeKind::ExprSlice, AnyNodeRef::ExprSlice(_) => NodeKind::ExprSlice,
AnyNodeRef::ExprLineMagic(_) => NodeKind::ExprLineMagic, AnyNodeRef::ExprIpyEscapeCommand(_) => NodeKind::ExprIpyEscapeCommand,
AnyNodeRef::ExceptHandlerExceptHandler(_) => NodeKind::ExceptHandlerExceptHandler, AnyNodeRef::ExceptHandlerExceptHandler(_) => NodeKind::ExceptHandlerExceptHandler,
AnyNodeRef::PatternMatchValue(_) => NodeKind::PatternMatchValue, AnyNodeRef::PatternMatchValue(_) => NodeKind::PatternMatchValue,
AnyNodeRef::PatternMatchSingleton(_) => NodeKind::PatternMatchSingleton, AnyNodeRef::PatternMatchSingleton(_) => NodeKind::PatternMatchSingleton,
@ -3831,7 +3831,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_) | AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_) | AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_) => true, | AnyNodeRef::StmtIpyEscapeCommand(_) => true,
AnyNodeRef::ModModule(_) AnyNodeRef::ModModule(_)
| AnyNodeRef::ModExpression(_) | AnyNodeRef::ModExpression(_)
@ -3862,7 +3862,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_) | AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_) | AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_) | AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_) | AnyNodeRef::ExprIpyEscapeCommand(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_) | AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSingleton(_)
@ -3919,7 +3919,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_) | AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_) | AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_) | AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_) => true, | AnyNodeRef::ExprIpyEscapeCommand(_) => true,
AnyNodeRef::ModModule(_) AnyNodeRef::ModModule(_)
| AnyNodeRef::ModExpression(_) | AnyNodeRef::ModExpression(_)
@ -3948,7 +3948,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_) | AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_) | AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_) | AnyNodeRef::StmtIpyEscapeCommand(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_) | AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSingleton(_)
@ -4005,7 +4005,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_) | AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_) | AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_) | AnyNodeRef::StmtIpyEscapeCommand(_)
| AnyNodeRef::ExprBoolOp(_) | AnyNodeRef::ExprBoolOp(_)
| AnyNodeRef::ExprNamedExpr(_) | AnyNodeRef::ExprNamedExpr(_)
| AnyNodeRef::ExprBinOp(_) | AnyNodeRef::ExprBinOp(_)
@ -4033,7 +4033,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_) | AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_) | AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_) | AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_) | AnyNodeRef::ExprIpyEscapeCommand(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_) | AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSingleton(_)
@ -4099,7 +4099,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_) | AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_) | AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_) | AnyNodeRef::StmtIpyEscapeCommand(_)
| AnyNodeRef::ExprBoolOp(_) | AnyNodeRef::ExprBoolOp(_)
| AnyNodeRef::ExprNamedExpr(_) | AnyNodeRef::ExprNamedExpr(_)
| AnyNodeRef::ExprBinOp(_) | AnyNodeRef::ExprBinOp(_)
@ -4127,7 +4127,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_) | AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_) | AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_) | AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_) | AnyNodeRef::ExprIpyEscapeCommand(_)
| AnyNodeRef::ExceptHandlerExceptHandler(_) | AnyNodeRef::ExceptHandlerExceptHandler(_)
| AnyNodeRef::Comprehension(_) | AnyNodeRef::Comprehension(_)
| AnyNodeRef::Arguments(_) | AnyNodeRef::Arguments(_)
@ -4178,7 +4178,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::StmtPass(_) | AnyNodeRef::StmtPass(_)
| AnyNodeRef::StmtBreak(_) | AnyNodeRef::StmtBreak(_)
| AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtContinue(_)
| AnyNodeRef::StmtLineMagic(_) | AnyNodeRef::StmtIpyEscapeCommand(_)
| AnyNodeRef::ExprBoolOp(_) | AnyNodeRef::ExprBoolOp(_)
| AnyNodeRef::ExprNamedExpr(_) | AnyNodeRef::ExprNamedExpr(_)
| AnyNodeRef::ExprBinOp(_) | AnyNodeRef::ExprBinOp(_)
@ -4206,7 +4206,7 @@ impl AnyNodeRef<'_> {
| AnyNodeRef::ExprList(_) | AnyNodeRef::ExprList(_)
| AnyNodeRef::ExprTuple(_) | AnyNodeRef::ExprTuple(_)
| AnyNodeRef::ExprSlice(_) | AnyNodeRef::ExprSlice(_)
| AnyNodeRef::ExprLineMagic(_) | AnyNodeRef::ExprIpyEscapeCommand(_)
| AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchValue(_)
| AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSingleton(_)
| AnyNodeRef::PatternMatchSequence(_) | AnyNodeRef::PatternMatchSequence(_)
@ -4429,9 +4429,9 @@ impl<'a> From<&'a ast::StmtContinue> for AnyNodeRef<'a> {
} }
} }
impl<'a> From<&'a ast::StmtLineMagic> for AnyNodeRef<'a> { impl<'a> From<&'a ast::StmtIpyEscapeCommand> for AnyNodeRef<'a> {
fn from(node: &'a ast::StmtLineMagic) -> Self { fn from(node: &'a ast::StmtIpyEscapeCommand) -> Self {
AnyNodeRef::StmtLineMagic(node) AnyNodeRef::StmtIpyEscapeCommand(node)
} }
} }
@ -4597,9 +4597,9 @@ impl<'a> From<&'a ast::ExprSlice> for AnyNodeRef<'a> {
} }
} }
impl<'a> From<&'a ast::ExprLineMagic> for AnyNodeRef<'a> { impl<'a> From<&'a ast::ExprIpyEscapeCommand> for AnyNodeRef<'a> {
fn from(node: &'a ast::ExprLineMagic) -> Self { fn from(node: &'a ast::ExprIpyEscapeCommand) -> Self {
AnyNodeRef::ExprLineMagic(node) AnyNodeRef::ExprIpyEscapeCommand(node)
} }
} }
@ -4714,7 +4714,7 @@ impl<'a> From<&'a Stmt> for AnyNodeRef<'a> {
Stmt::Pass(node) => AnyNodeRef::StmtPass(node), Stmt::Pass(node) => AnyNodeRef::StmtPass(node),
Stmt::Break(node) => AnyNodeRef::StmtBreak(node), Stmt::Break(node) => AnyNodeRef::StmtBreak(node),
Stmt::Continue(node) => AnyNodeRef::StmtContinue(node), Stmt::Continue(node) => AnyNodeRef::StmtContinue(node),
Stmt::LineMagic(node) => AnyNodeRef::StmtLineMagic(node), Stmt::IpyEscapeCommand(node) => AnyNodeRef::StmtIpyEscapeCommand(node),
} }
} }
} }
@ -4749,7 +4749,7 @@ impl<'a> From<&'a Expr> for AnyNodeRef<'a> {
Expr::List(node) => AnyNodeRef::ExprList(node), Expr::List(node) => AnyNodeRef::ExprList(node),
Expr::Tuple(node) => AnyNodeRef::ExprTuple(node), Expr::Tuple(node) => AnyNodeRef::ExprTuple(node),
Expr::Slice(node) => AnyNodeRef::ExprSlice(node), Expr::Slice(node) => AnyNodeRef::ExprSlice(node),
Expr::LineMagic(node) => AnyNodeRef::ExprLineMagic(node), Expr::IpyEscapeCommand(node) => AnyNodeRef::ExprIpyEscapeCommand(node),
} }
} }
} }
@ -4874,7 +4874,7 @@ impl Ranged for AnyNodeRef<'_> {
AnyNodeRef::StmtPass(node) => node.range(), AnyNodeRef::StmtPass(node) => node.range(),
AnyNodeRef::StmtBreak(node) => node.range(), AnyNodeRef::StmtBreak(node) => node.range(),
AnyNodeRef::StmtContinue(node) => node.range(), AnyNodeRef::StmtContinue(node) => node.range(),
AnyNodeRef::StmtLineMagic(node) => node.range(), AnyNodeRef::StmtIpyEscapeCommand(node) => node.range(),
AnyNodeRef::ExprBoolOp(node) => node.range(), AnyNodeRef::ExprBoolOp(node) => node.range(),
AnyNodeRef::ExprNamedExpr(node) => node.range(), AnyNodeRef::ExprNamedExpr(node) => node.range(),
AnyNodeRef::ExprBinOp(node) => node.range(), AnyNodeRef::ExprBinOp(node) => node.range(),
@ -4902,7 +4902,7 @@ impl Ranged for AnyNodeRef<'_> {
AnyNodeRef::ExprList(node) => node.range(), AnyNodeRef::ExprList(node) => node.range(),
AnyNodeRef::ExprTuple(node) => node.range(), AnyNodeRef::ExprTuple(node) => node.range(),
AnyNodeRef::ExprSlice(node) => node.range(), AnyNodeRef::ExprSlice(node) => node.range(),
AnyNodeRef::ExprLineMagic(node) => node.range(), AnyNodeRef::ExprIpyEscapeCommand(node) => node.range(),
AnyNodeRef::ExceptHandlerExceptHandler(node) => node.range(), AnyNodeRef::ExceptHandlerExceptHandler(node) => node.range(),
AnyNodeRef::PatternMatchValue(node) => node.range(), AnyNodeRef::PatternMatchValue(node) => node.range(),
AnyNodeRef::PatternMatchSingleton(node) => node.range(), AnyNodeRef::PatternMatchSingleton(node) => node.range(),
@ -4958,7 +4958,7 @@ pub enum NodeKind {
StmtImportFrom, StmtImportFrom,
StmtGlobal, StmtGlobal,
StmtNonlocal, StmtNonlocal,
StmtLineMagic, StmtIpyEscapeCommand,
StmtExpr, StmtExpr,
StmtPass, StmtPass,
StmtBreak, StmtBreak,
@ -4990,7 +4990,7 @@ pub enum NodeKind {
ExprList, ExprList,
ExprTuple, ExprTuple,
ExprSlice, ExprSlice,
ExprLineMagic, ExprIpyEscapeCommand,
ExceptHandlerExceptHandler, ExceptHandlerExceptHandler,
PatternMatchValue, PatternMatchValue,
PatternMatchSingleton, PatternMatchSingleton,

View file

@ -95,20 +95,20 @@ pub enum Stmt {
Continue(StmtContinue), Continue(StmtContinue),
// Jupyter notebook specific // Jupyter notebook specific
#[is(name = "line_magic_stmt")] #[is(name = "ipy_escape_command_stmt")]
LineMagic(StmtLineMagic), IpyEscapeCommand(StmtIpyEscapeCommand),
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct StmtLineMagic { pub struct StmtIpyEscapeCommand {
pub range: TextRange, pub range: TextRange,
pub kind: MagicKind, pub kind: IpyEscapeKind,
pub value: String, pub value: String,
} }
impl From<StmtLineMagic> for Stmt { impl From<StmtIpyEscapeCommand> for Stmt {
fn from(payload: StmtLineMagic) -> Self { fn from(payload: StmtIpyEscapeCommand) -> Self {
Stmt::LineMagic(payload) Stmt::IpyEscapeCommand(payload)
} }
} }
@ -570,20 +570,20 @@ pub enum Expr {
Slice(ExprSlice), Slice(ExprSlice),
// Jupyter notebook specific // Jupyter notebook specific
#[is(name = "line_magic_expr")] #[is(name = "ipy_escape_command_expr")]
LineMagic(ExprLineMagic), IpyEscapeCommand(ExprIpyEscapeCommand),
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ExprLineMagic { pub struct ExprIpyEscapeCommand {
pub range: TextRange, pub range: TextRange,
pub kind: MagicKind, pub kind: IpyEscapeKind,
pub value: String, pub value: String,
} }
impl From<ExprLineMagic> for Expr { impl From<ExprIpyEscapeCommand> for Expr {
fn from(payload: ExprLineMagic) -> Self { fn from(payload: ExprIpyEscapeCommand) -> Self {
Expr::LineMagic(payload) Expr::IpyEscapeCommand(payload)
} }
} }
@ -2253,103 +2253,103 @@ impl Parameters {
} }
} }
/// The kind of magic command as defined in [IPython Syntax] in the IPython codebase. /// The kind of escape command as defined in [IPython Syntax] in the IPython codebase.
/// ///
/// [IPython Syntax]: https://github.com/ipython/ipython/blob/635815e8f1ded5b764d66cacc80bbe25e9e2587f/IPython/core/inputtransformer2.py#L335-L343 /// [IPython Syntax]: https://github.com/ipython/ipython/blob/635815e8f1ded5b764d66cacc80bbe25e9e2587f/IPython/core/inputtransformer2.py#L335-L343
#[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)] #[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)]
pub enum MagicKind { pub enum IpyEscapeKind {
/// Send line to underlying system shell. /// Send line to underlying system shell (`!`).
Shell, Shell,
/// Send line to system shell and capture output. /// Send line to system shell and capture output (`!!`).
ShCap, ShCap,
/// Show help on object. /// Show help on object (`?`).
Help, Help,
/// Show help on object, with extra verbosity. /// Show help on object, with extra verbosity (`??`).
Help2, Help2,
/// Call magic function. /// Call magic function (`%`).
Magic, Magic,
/// Call cell magic function. /// Call cell magic function (`%%`).
Magic2, Magic2,
/// Call first argument with rest of line as arguments after splitting on whitespace /// Call first argument with rest of line as arguments after splitting on whitespace
/// and quote each as string. /// and quote each as string (`,`).
Quote, Quote,
/// Call first argument with rest of line as an argument quoted as a single string. /// Call first argument with rest of line as an argument quoted as a single string (`;`).
Quote2, Quote2,
/// Call first argument with rest of line as arguments. /// Call first argument with rest of line as arguments (`/`).
Paren, Paren,
} }
impl TryFrom<char> for MagicKind { impl TryFrom<char> for IpyEscapeKind {
type Error = String; type Error = String;
fn try_from(ch: char) -> Result<Self, Self::Error> { fn try_from(ch: char) -> Result<Self, Self::Error> {
match ch { match ch {
'!' => Ok(MagicKind::Shell), '!' => Ok(IpyEscapeKind::Shell),
'?' => Ok(MagicKind::Help), '?' => Ok(IpyEscapeKind::Help),
'%' => Ok(MagicKind::Magic), '%' => Ok(IpyEscapeKind::Magic),
',' => Ok(MagicKind::Quote), ',' => Ok(IpyEscapeKind::Quote),
';' => Ok(MagicKind::Quote2), ';' => Ok(IpyEscapeKind::Quote2),
'/' => Ok(MagicKind::Paren), '/' => Ok(IpyEscapeKind::Paren),
_ => Err(format!("Unexpected magic escape: {ch}")), _ => Err(format!("Unexpected magic escape: {ch}")),
} }
} }
} }
impl TryFrom<[char; 2]> for MagicKind { impl TryFrom<[char; 2]> for IpyEscapeKind {
type Error = String; type Error = String;
fn try_from(ch: [char; 2]) -> Result<Self, Self::Error> { fn try_from(ch: [char; 2]) -> Result<Self, Self::Error> {
match ch { match ch {
['!', '!'] => Ok(MagicKind::ShCap), ['!', '!'] => Ok(IpyEscapeKind::ShCap),
['?', '?'] => Ok(MagicKind::Help2), ['?', '?'] => Ok(IpyEscapeKind::Help2),
['%', '%'] => Ok(MagicKind::Magic2), ['%', '%'] => Ok(IpyEscapeKind::Magic2),
[c1, c2] => Err(format!("Unexpected magic escape: {c1}{c2}")), [c1, c2] => Err(format!("Unexpected magic escape: {c1}{c2}")),
} }
} }
} }
impl fmt::Display for MagicKind { impl fmt::Display for IpyEscapeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str()) f.write_str(self.as_str())
} }
} }
impl MagicKind { impl IpyEscapeKind {
/// Returns the length of the magic command prefix. /// Returns the length of the escape kind token.
pub fn prefix_len(self) -> TextSize { pub fn prefix_len(self) -> TextSize {
let len = match self { let len = match self {
MagicKind::Shell IpyEscapeKind::Shell
| MagicKind::Magic | IpyEscapeKind::Magic
| MagicKind::Help | IpyEscapeKind::Help
| MagicKind::Quote | IpyEscapeKind::Quote
| MagicKind::Quote2 | IpyEscapeKind::Quote2
| MagicKind::Paren => 1, | IpyEscapeKind::Paren => 1,
MagicKind::ShCap | MagicKind::Magic2 | MagicKind::Help2 => 2, IpyEscapeKind::ShCap | IpyEscapeKind::Magic2 | IpyEscapeKind::Help2 => 2,
}; };
len.into() len.into()
} }
/// Returns `true` if the kind is a help command i.e., `?` or `??`. /// Returns `true` if the escape kind is help i.e., `?` or `??`.
pub const fn is_help(self) -> bool { pub const fn is_help(self) -> bool {
matches!(self, MagicKind::Help | MagicKind::Help2) matches!(self, IpyEscapeKind::Help | IpyEscapeKind::Help2)
} }
/// Returns `true` if the kind is a magic command i.e., `%` or `%%`. /// Returns `true` if the escape kind is magic i.e., `%` or `%%`.
pub const fn is_magic(self) -> bool { pub const fn is_magic(self) -> bool {
matches!(self, MagicKind::Magic | MagicKind::Magic2) matches!(self, IpyEscapeKind::Magic | IpyEscapeKind::Magic2)
} }
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
MagicKind::Shell => "!", IpyEscapeKind::Shell => "!",
MagicKind::ShCap => "!!", IpyEscapeKind::ShCap => "!!",
MagicKind::Help => "?", IpyEscapeKind::Help => "?",
MagicKind::Help2 => "??", IpyEscapeKind::Help2 => "??",
MagicKind::Magic => "%", IpyEscapeKind::Magic => "%",
MagicKind::Magic2 => "%%", IpyEscapeKind::Magic2 => "%%",
MagicKind::Quote => ",", IpyEscapeKind::Quote => ",",
MagicKind::Quote2 => ";", IpyEscapeKind::Quote2 => ";",
MagicKind::Paren => "/", IpyEscapeKind::Paren => "/",
} }
} }
} }
@ -2686,7 +2686,7 @@ impl Ranged for crate::nodes::StmtContinue {
self.range self.range
} }
} }
impl Ranged for StmtLineMagic { impl Ranged for StmtIpyEscapeCommand {
fn range(&self) -> TextRange { fn range(&self) -> TextRange {
self.range self.range
} }
@ -2719,7 +2719,7 @@ impl Ranged for crate::Stmt {
Self::Pass(node) => node.range(), Self::Pass(node) => node.range(),
Self::Break(node) => node.range(), Self::Break(node) => node.range(),
Self::Continue(node) => node.range(), Self::Continue(node) => node.range(),
Stmt::LineMagic(node) => node.range(), Stmt::IpyEscapeCommand(node) => node.range(),
} }
} }
} }
@ -2859,7 +2859,7 @@ impl Ranged for crate::nodes::ExprSlice {
self.range self.range
} }
} }
impl Ranged for ExprLineMagic { impl Ranged for ExprIpyEscapeCommand {
fn range(&self) -> TextRange { fn range(&self) -> TextRange {
self.range self.range
} }
@ -2894,7 +2894,7 @@ impl Ranged for crate::Expr {
Self::List(node) => node.range(), Self::List(node) => node.range(),
Self::Tuple(node) => node.range(), Self::Tuple(node) => node.range(),
Self::Slice(node) => node.range(), Self::Slice(node) => node.range(),
Expr::LineMagic(node) => node.range(), Expr::IpyEscapeCommand(node) => node.range(),
} }
} }
} }

View file

@ -199,7 +199,7 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) {
relocate_expr(expr, location); relocate_expr(expr, location);
} }
} }
Expr::LineMagic(nodes::ExprLineMagic { range, .. }) => { Expr::IpyEscapeCommand(nodes::ExprIpyEscapeCommand { range, .. }) => {
*range = location; *range = location;
} }
} }

View file

@ -312,7 +312,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
Stmt::Global(_) => {} Stmt::Global(_) => {}
Stmt::Nonlocal(_) => {} Stmt::Nonlocal(_) => {}
Stmt::Expr(ast::StmtExpr { value, range: _ }) => visitor.visit_expr(value), Stmt::Expr(ast::StmtExpr { value, range: _ }) => visitor.visit_expr(value),
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) | Stmt::LineMagic(_) => {} Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) | Stmt::IpyEscapeCommand(_) => {}
} }
} }
@ -543,7 +543,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
visitor.visit_expr(expr); visitor.visit_expr(expr);
} }
} }
Expr::LineMagic(_) => {} Expr::IpyEscapeCommand(_) => {}
} }
} }

View file

@ -418,7 +418,7 @@ where
| Stmt::Continue(_) | Stmt::Continue(_)
| Stmt::Global(_) | Stmt::Global(_)
| Stmt::Nonlocal(_) | Stmt::Nonlocal(_)
| Stmt::LineMagic(_) => {} | Stmt::IpyEscapeCommand(_) => {}
} }
} }
@ -719,7 +719,7 @@ where
visitor.visit_expr(expr); visitor.visit_expr(expr);
} }
} }
Expr::LineMagic(_) => (), Expr::IpyEscapeCommand(_) => (),
} }
} }

View file

@ -656,7 +656,7 @@ impl<'a> Generator<'a> {
self.p("continue"); self.p("continue");
}); });
} }
Stmt::LineMagic(ast::StmtLineMagic { kind, value, .. }) => { Stmt::IpyEscapeCommand(ast::StmtIpyEscapeCommand { kind, value, .. }) => {
statement!({ statement!({
self.p(&format!("{kind}{value}")); self.p(&format!("{kind}{value}"));
}); });
@ -1184,7 +1184,7 @@ impl<'a> Generator<'a> {
self.unparse_expr(step, precedence::SLICE); self.unparse_expr(step, precedence::SLICE);
} }
} }
Expr::LineMagic(ast::ExprLineMagic { kind, value, .. }) => { Expr::IpyEscapeCommand(ast::ExprIpyEscapeCommand { kind, value, .. }) => {
self.p(&format!("{kind}{value}")); self.p(&format!("{kind}{value}"));
} }
} }

View file

@ -0,0 +1,12 @@
use crate::{verbatim_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::ExprIpyEscapeCommand;
#[derive(Default)]
pub struct FormatExprIpyEscapeCommand;
impl FormatNodeRule<ExprIpyEscapeCommand> for FormatExprIpyEscapeCommand {
fn fmt_fields(&self, item: &ExprIpyEscapeCommand, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [verbatim_text(item)])
}
}

View file

@ -1,12 +0,0 @@
use crate::{verbatim_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::ExprLineMagic;
#[derive(Default)]
pub struct FormatExprLineMagic;
impl FormatNodeRule<ExprLineMagic> for FormatExprLineMagic {
fn fmt_fields(&self, item: &ExprLineMagic, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [verbatim_text(item)])
}
}

View file

@ -31,8 +31,8 @@ pub(crate) mod expr_f_string;
pub(crate) mod expr_formatted_value; pub(crate) mod expr_formatted_value;
pub(crate) mod expr_generator_exp; pub(crate) mod expr_generator_exp;
pub(crate) mod expr_if_exp; pub(crate) mod expr_if_exp;
pub(crate) mod expr_ipy_escape_command;
pub(crate) mod expr_lambda; pub(crate) mod expr_lambda;
pub(crate) mod expr_line_magic;
pub(crate) mod expr_list; pub(crate) mod expr_list;
pub(crate) mod expr_list_comp; pub(crate) mod expr_list_comp;
pub(crate) mod expr_name; pub(crate) mod expr_name;
@ -102,7 +102,7 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
Expr::List(expr) => expr.format().fmt(f), Expr::List(expr) => expr.format().fmt(f),
Expr::Tuple(expr) => expr.format().fmt(f), Expr::Tuple(expr) => expr.format().fmt(f),
Expr::Slice(expr) => expr.format().fmt(f), Expr::Slice(expr) => expr.format().fmt(f),
Expr::LineMagic(_) => todo!(), Expr::IpyEscapeCommand(_) => todo!(),
}); });
let parenthesize = match parentheses { let parenthesize = match parentheses {
@ -240,7 +240,7 @@ impl NeedsParentheses for Expr {
Expr::List(expr) => expr.needs_parentheses(parent, context), Expr::List(expr) => expr.needs_parentheses(parent, context),
Expr::Tuple(expr) => expr.needs_parentheses(parent, context), Expr::Tuple(expr) => expr.needs_parentheses(parent, context),
Expr::Slice(expr) => expr.needs_parentheses(parent, context), Expr::Slice(expr) => expr.needs_parentheses(parent, context),
Expr::LineMagic(_) => todo!(), Expr::IpyEscapeCommand(_) => todo!(),
} }
} }
} }
@ -434,7 +434,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
| Expr::Starred(_) | Expr::Starred(_)
| Expr::Name(_) | Expr::Name(_)
| Expr::Slice(_) => {} | Expr::Slice(_) => {}
Expr::LineMagic(_) => todo!(), Expr::IpyEscapeCommand(_) => todo!(),
}; };
walk_expr(self, expr); walk_expr(self, expr);

View file

@ -930,38 +930,38 @@ impl<'ast> IntoFormat<PyFormatContext<'ast>> for ast::StmtContinue {
} }
} }
impl FormatRule<ast::StmtLineMagic, PyFormatContext<'_>> impl FormatRule<ast::StmtIpyEscapeCommand, PyFormatContext<'_>>
for crate::statement::stmt_line_magic::FormatStmtLineMagic for crate::statement::stmt_ipy_escape_command::FormatStmtIpyEscapeCommand
{ {
#[inline] #[inline]
fn fmt(&self, node: &ast::StmtLineMagic, f: &mut PyFormatter) -> FormatResult<()> { fn fmt(&self, node: &ast::StmtIpyEscapeCommand, f: &mut PyFormatter) -> FormatResult<()> {
FormatNodeRule::<ast::StmtLineMagic>::fmt(self, node, f) FormatNodeRule::<ast::StmtIpyEscapeCommand>::fmt(self, node, f)
} }
} }
impl<'ast> AsFormat<PyFormatContext<'ast>> for ast::StmtLineMagic { impl<'ast> AsFormat<PyFormatContext<'ast>> for ast::StmtIpyEscapeCommand {
type Format<'a> = FormatRefWithRule< type Format<'a> = FormatRefWithRule<
'a, 'a,
ast::StmtLineMagic, ast::StmtIpyEscapeCommand,
crate::statement::stmt_line_magic::FormatStmtLineMagic, crate::statement::stmt_ipy_escape_command::FormatStmtIpyEscapeCommand,
PyFormatContext<'ast>, PyFormatContext<'ast>,
>; >;
fn format(&self) -> Self::Format<'_> { fn format(&self) -> Self::Format<'_> {
FormatRefWithRule::new( FormatRefWithRule::new(
self, self,
crate::statement::stmt_line_magic::FormatStmtLineMagic::default(), crate::statement::stmt_ipy_escape_command::FormatStmtIpyEscapeCommand::default(),
) )
} }
} }
impl<'ast> IntoFormat<PyFormatContext<'ast>> for ast::StmtLineMagic { impl<'ast> IntoFormat<PyFormatContext<'ast>> for ast::StmtIpyEscapeCommand {
type Format = FormatOwnedWithRule< type Format = FormatOwnedWithRule<
ast::StmtLineMagic, ast::StmtIpyEscapeCommand,
crate::statement::stmt_line_magic::FormatStmtLineMagic, crate::statement::stmt_ipy_escape_command::FormatStmtIpyEscapeCommand,
PyFormatContext<'ast>, PyFormatContext<'ast>,
>; >;
fn into_format(self) -> Self::Format { fn into_format(self) -> Self::Format {
FormatOwnedWithRule::new( FormatOwnedWithRule::new(
self, self,
crate::statement::stmt_line_magic::FormatStmtLineMagic::default(), crate::statement::stmt_ipy_escape_command::FormatStmtIpyEscapeCommand::default(),
) )
} }
} }
@ -1930,38 +1930,38 @@ impl<'ast> IntoFormat<PyFormatContext<'ast>> for ast::ExprSlice {
} }
} }
impl FormatRule<ast::ExprLineMagic, PyFormatContext<'_>> impl FormatRule<ast::ExprIpyEscapeCommand, PyFormatContext<'_>>
for crate::expression::expr_line_magic::FormatExprLineMagic for crate::expression::expr_ipy_escape_command::FormatExprIpyEscapeCommand
{ {
#[inline] #[inline]
fn fmt(&self, node: &ast::ExprLineMagic, f: &mut PyFormatter) -> FormatResult<()> { fn fmt(&self, node: &ast::ExprIpyEscapeCommand, f: &mut PyFormatter) -> FormatResult<()> {
FormatNodeRule::<ast::ExprLineMagic>::fmt(self, node, f) FormatNodeRule::<ast::ExprIpyEscapeCommand>::fmt(self, node, f)
} }
} }
impl<'ast> AsFormat<PyFormatContext<'ast>> for ast::ExprLineMagic { impl<'ast> AsFormat<PyFormatContext<'ast>> for ast::ExprIpyEscapeCommand {
type Format<'a> = FormatRefWithRule< type Format<'a> = FormatRefWithRule<
'a, 'a,
ast::ExprLineMagic, ast::ExprIpyEscapeCommand,
crate::expression::expr_line_magic::FormatExprLineMagic, crate::expression::expr_ipy_escape_command::FormatExprIpyEscapeCommand,
PyFormatContext<'ast>, PyFormatContext<'ast>,
>; >;
fn format(&self) -> Self::Format<'_> { fn format(&self) -> Self::Format<'_> {
FormatRefWithRule::new( FormatRefWithRule::new(
self, self,
crate::expression::expr_line_magic::FormatExprLineMagic::default(), crate::expression::expr_ipy_escape_command::FormatExprIpyEscapeCommand::default(),
) )
} }
} }
impl<'ast> IntoFormat<PyFormatContext<'ast>> for ast::ExprLineMagic { impl<'ast> IntoFormat<PyFormatContext<'ast>> for ast::ExprIpyEscapeCommand {
type Format = FormatOwnedWithRule< type Format = FormatOwnedWithRule<
ast::ExprLineMagic, ast::ExprIpyEscapeCommand,
crate::expression::expr_line_magic::FormatExprLineMagic, crate::expression::expr_ipy_escape_command::FormatExprIpyEscapeCommand,
PyFormatContext<'ast>, PyFormatContext<'ast>,
>; >;
fn into_format(self) -> Self::Format { fn into_format(self) -> Self::Format {
FormatOwnedWithRule::new( FormatOwnedWithRule::new(
self, self,
crate::expression::expr_line_magic::FormatExprLineMagic::default(), crate::expression::expr_ipy_escape_command::FormatExprIpyEscapeCommand::default(),
) )
} }
} }

View file

@ -17,7 +17,7 @@ pub(crate) mod stmt_global;
pub(crate) mod stmt_if; pub(crate) mod stmt_if;
pub(crate) mod stmt_import; pub(crate) mod stmt_import;
pub(crate) mod stmt_import_from; pub(crate) mod stmt_import_from;
pub(crate) mod stmt_line_magic; pub(crate) mod stmt_ipy_escape_command;
pub(crate) mod stmt_match; pub(crate) mod stmt_match;
pub(crate) mod stmt_nonlocal; pub(crate) mod stmt_nonlocal;
pub(crate) mod stmt_pass; pub(crate) mod stmt_pass;
@ -61,7 +61,7 @@ impl FormatRule<Stmt, PyFormatContext<'_>> for FormatStmt {
Stmt::Break(x) => x.format().fmt(f), Stmt::Break(x) => x.format().fmt(f),
Stmt::Continue(x) => x.format().fmt(f), Stmt::Continue(x) => x.format().fmt(f),
Stmt::TypeAlias(x) => x.format().fmt(f), Stmt::TypeAlias(x) => x.format().fmt(f),
Stmt::LineMagic(_) => todo!(), Stmt::IpyEscapeCommand(_) => todo!(),
} }
} }
} }

View file

@ -0,0 +1,12 @@
use crate::{verbatim_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::StmtIpyEscapeCommand;
#[derive(Default)]
pub struct FormatStmtIpyEscapeCommand;
impl FormatNodeRule<StmtIpyEscapeCommand> for FormatStmtIpyEscapeCommand {
fn fmt_fields(&self, item: &StmtIpyEscapeCommand, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [verbatim_text(item)])
}
}

View file

@ -1,12 +0,0 @@
use crate::{verbatim_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::StmtLineMagic;
#[derive(Default)]
pub struct FormatStmtLineMagic;
impl FormatNodeRule<StmtLineMagic> for FormatStmtLineMagic {
fn fmt_fields(&self, item: &StmtLineMagic, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [verbatim_text(item)])
}
}

View file

@ -34,7 +34,7 @@ use std::{char, cmp::Ordering, str::FromStr};
use num_bigint::BigInt; use num_bigint::BigInt;
use num_traits::{Num, Zero}; use num_traits::{Num, Zero};
use ruff_python_ast::MagicKind; use ruff_python_ast::IpyEscapeKind;
use ruff_text_size::{TextLen, TextRange, TextSize}; use ruff_text_size::{TextLen, TextRange, TextSize};
use unic_emoji_char::is_emoji_presentation; use unic_emoji_char::is_emoji_presentation;
use unic_ucd_ident::{is_xid_continue, is_xid_start}; use unic_ucd_ident::{is_xid_continue, is_xid_start};
@ -398,8 +398,8 @@ impl<'source> Lexer<'source> {
Tok::Comment(self.token_text().to_string()) Tok::Comment(self.token_text().to_string())
} }
/// Lex a single magic command. /// Lex a single IPython escape command.
fn lex_magic_command(&mut self, kind: MagicKind) -> Tok { fn lex_ipython_escape_command(&mut self, escape_kind: IpyEscapeKind) -> Tok {
let mut value = String::new(); let mut value = String::new();
loop { loop {
@ -457,7 +457,7 @@ impl<'source> Lexer<'source> {
// Now, the whitespace and empty value check also makes sure that an empty // Now, the whitespace and empty value check also makes sure that an empty
// command (e.g. `%?` or `? ??`, no value after/between the escape tokens) // command (e.g. `%?` or `? ??`, no value after/between the escape tokens)
// is not recognized as a help end escape command. So, `%?` and `? ??` are // is not recognized as a help end escape command. So, `%?` and `? ??` are
// `MagicKind::Magic` and `MagicKind::Help` because of the initial `%` and `??` // `IpyEscapeKind::Magic` and `IpyEscapeKind::Help` because of the initial `%` and `??`
// tokens. // tokens.
if question_count > 2 if question_count > 2
|| value.chars().last().map_or(true, is_python_whitespace) || value.chars().last().map_or(true, is_python_whitespace)
@ -471,31 +471,34 @@ impl<'source> Lexer<'source> {
continue; continue;
} }
if kind.is_help() { if escape_kind.is_help() {
// If we've recognize this as a help end escape command, then // If we've recognize this as a help end escape command, then
// any question mark token / whitespaces at the start are not // any question mark token / whitespaces at the start are not
// considered as part of the value. // considered as part of the value.
// //
// For example, `??foo?` is recognized as `MagicKind::Help` and // For example, `??foo?` is recognized as `IpyEscapeKind::Help` and
// `value` is `foo` instead of `??foo`. // `value` is `foo` instead of `??foo`.
value = value.trim_start_matches([' ', '?']).to_string(); value = value.trim_start_matches([' ', '?']).to_string();
} else if kind.is_magic() { } else if escape_kind.is_magic() {
// Between `%` and `?` (at the end), the `?` takes priority // Between `%` and `?` (at the end), the `?` takes priority
// over the `%` so `%foo?` is recognized as `MagicKind::Help` // over the `%` so `%foo?` is recognized as `IpyEscapeKind::Help`
// and `value` is `%foo` instead of `foo`. So, we need to // and `value` is `%foo` instead of `foo`. So, we need to
// insert the magic escape token at the start. // insert the magic escape token at the start.
value.insert_str(0, kind.as_str()); value.insert_str(0, escape_kind.as_str());
} }
let kind = match question_count { let kind = match question_count {
1 => MagicKind::Help, 1 => IpyEscapeKind::Help,
2 => MagicKind::Help2, 2 => IpyEscapeKind::Help2,
_ => unreachable!("`question_count` is always 1 or 2"), _ => unreachable!("`question_count` is always 1 or 2"),
}; };
return Tok::MagicCommand { kind, value }; return Tok::IpyEscapeCommand { kind, value };
} }
'\n' | '\r' | EOF_CHAR => { '\n' | '\r' | EOF_CHAR => {
return Tok::MagicCommand { kind, value }; return Tok::IpyEscapeCommand {
kind: escape_kind,
value,
};
} }
c => { c => {
self.cursor.bump(); self.cursor.bump();
@ -763,22 +766,22 @@ impl<'source> Lexer<'source> {
&& self.state.is_after_equal() && self.state.is_after_equal()
&& self.nesting == 0 => && self.nesting == 0 =>
{ {
// SAFETY: Safe because `c` has been matched against one of the possible magic command prefix // SAFETY: Safe because `c` has been matched against one of the possible escape command token
self.lex_magic_command(MagicKind::try_from(c).unwrap()) self.lex_ipython_escape_command(IpyEscapeKind::try_from(c).unwrap())
} }
c @ ('%' | '!' | '?' | '/' | ';' | ',') c @ ('%' | '!' | '?' | '/' | ';' | ',')
if self.mode == Mode::Jupyter && self.state.is_new_logical_line() => if self.mode == Mode::Jupyter && self.state.is_new_logical_line() =>
{ {
let kind = if let Ok(kind) = MagicKind::try_from([c, self.cursor.first()]) { let kind = if let Ok(kind) = IpyEscapeKind::try_from([c, self.cursor.first()]) {
self.cursor.bump(); self.cursor.bump();
kind kind
} else { } else {
// SAFETY: Safe because `c` has been matched against one of the possible magic command prefix // SAFETY: Safe because `c` has been matched against one of the possible escape command token
MagicKind::try_from(c).unwrap() IpyEscapeKind::try_from(c).unwrap()
}; };
self.lex_magic_command(kind) self.lex_ipython_escape_command(kind)
} }
'?' if self.mode == Mode::Jupyter => Tok::Question, '?' if self.mode == Mode::Jupyter => Tok::Question,
@ -1208,7 +1211,7 @@ const fn is_python_whitespace(c: char) -> bool {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use num_bigint::BigInt; use num_bigint::BigInt;
use ruff_python_ast::MagicKind; use ruff_python_ast::IpyEscapeKind;
use super::*; use super::*;
@ -1242,15 +1245,15 @@ mod tests {
} }
} }
fn assert_jupyter_magic_line_continuation_with_eol(eol: &str) { fn assert_ipython_escape_command_line_continuation_with_eol(eol: &str) {
let source = format!("%matplotlib \\{eol} --inline"); let source = format!("%matplotlib \\{eol} --inline");
let tokens = lex_jupyter_source(&source); let tokens = lex_jupyter_source(&source);
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "matplotlib --inline".to_string(), value: "matplotlib --inline".to_string(),
kind: MagicKind::Magic kind: IpyEscapeKind::Magic
}, },
Tok::Newline Tok::Newline
] ]
@ -1258,29 +1261,29 @@ mod tests {
} }
#[test] #[test]
fn test_jupyter_magic_line_continuation_unix_eol() { fn test_ipython_escape_command_line_continuation_unix_eol() {
assert_jupyter_magic_line_continuation_with_eol(UNIX_EOL); assert_ipython_escape_command_line_continuation_with_eol(UNIX_EOL);
} }
#[test] #[test]
fn test_jupyter_magic_line_continuation_mac_eol() { fn test_ipython_escape_command_line_continuation_mac_eol() {
assert_jupyter_magic_line_continuation_with_eol(MAC_EOL); assert_ipython_escape_command_line_continuation_with_eol(MAC_EOL);
} }
#[test] #[test]
fn test_jupyter_magic_line_continuation_windows_eol() { fn test_ipython_escape_command_line_continuation_windows_eol() {
assert_jupyter_magic_line_continuation_with_eol(WINDOWS_EOL); assert_ipython_escape_command_line_continuation_with_eol(WINDOWS_EOL);
} }
fn assert_jupyter_magic_line_continuation_with_eol_and_eof(eol: &str) { fn assert_ipython_escape_command_line_continuation_with_eol_and_eof(eol: &str) {
let source = format!("%matplotlib \\{eol}"); let source = format!("%matplotlib \\{eol}");
let tokens = lex_jupyter_source(&source); let tokens = lex_jupyter_source(&source);
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "matplotlib ".to_string(), value: "matplotlib ".to_string(),
kind: MagicKind::Magic kind: IpyEscapeKind::Magic
}, },
Tok::Newline Tok::Newline
] ]
@ -1288,70 +1291,70 @@ mod tests {
} }
#[test] #[test]
fn test_jupyter_magic_line_continuation_unix_eol_and_eof() { fn test_ipython_escape_command_line_continuation_unix_eol_and_eof() {
assert_jupyter_magic_line_continuation_with_eol_and_eof(UNIX_EOL); assert_ipython_escape_command_line_continuation_with_eol_and_eof(UNIX_EOL);
} }
#[test] #[test]
fn test_jupyter_magic_line_continuation_mac_eol_and_eof() { fn test_ipython_escape_command_line_continuation_mac_eol_and_eof() {
assert_jupyter_magic_line_continuation_with_eol_and_eof(MAC_EOL); assert_ipython_escape_command_line_continuation_with_eol_and_eof(MAC_EOL);
} }
#[test] #[test]
fn test_jupyter_magic_line_continuation_windows_eol_and_eof() { fn test_ipython_escape_command_line_continuation_windows_eol_and_eof() {
assert_jupyter_magic_line_continuation_with_eol_and_eof(WINDOWS_EOL); assert_ipython_escape_command_line_continuation_with_eol_and_eof(WINDOWS_EOL);
} }
#[test] #[test]
fn test_empty_jupyter_magic() { fn test_empty_ipython_escape_command() {
let source = "%\n%%\n!\n!!\n?\n??\n/\n,\n;"; let source = "%\n%%\n!\n!!\n?\n??\n/\n,\n;";
let tokens = lex_jupyter_source(source); let tokens = lex_jupyter_source(source);
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Magic2, kind: IpyEscapeKind::Magic2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Shell, kind: IpyEscapeKind::Shell,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::ShCap, kind: IpyEscapeKind::ShCap,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Paren, kind: IpyEscapeKind::Paren,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Quote, kind: IpyEscapeKind::Quote,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: String::new(), value: String::new(),
kind: MagicKind::Quote2, kind: IpyEscapeKind::Quote2,
}, },
Tok::Newline, Tok::Newline,
] ]
@ -1359,7 +1362,7 @@ mod tests {
} }
#[test] #[test]
fn test_jupyter_magic() { fn test_ipython_escape_command() {
let source = r" let source = r"
?foo ?foo
??foo ??foo
@ -1380,59 +1383,59 @@ mod tests {
assert_eq!( assert_eq!(
tokens, tokens,
vec![ vec![
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "timeit a = b".to_string(), value: "timeit a = b".to_string(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "timeit a % 3".to_string(), value: "timeit a % 3".to_string(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "matplotlib --inline".to_string(), value: "matplotlib --inline".to_string(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "pwd && ls -a | sed 's/^/\\\\ /'".to_string(), value: "pwd && ls -a | sed 's/^/\\\\ /'".to_string(),
kind: MagicKind::Shell, kind: IpyEscapeKind::Shell,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "cd /Users/foo/Library/Application\\ Support/".to_string(), value: "cd /Users/foo/Library/Application\\ Support/".to_string(),
kind: MagicKind::ShCap, kind: IpyEscapeKind::ShCap,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo 1 2".to_string(), value: "foo 1 2".to_string(),
kind: MagicKind::Paren, kind: IpyEscapeKind::Paren,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo 1 2".to_string(), value: "foo 1 2".to_string(),
kind: MagicKind::Quote, kind: IpyEscapeKind::Quote,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo 1 2".to_string(), value: "foo 1 2".to_string(),
kind: MagicKind::Quote2, kind: IpyEscapeKind::Quote2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "ls".to_string(), value: "ls".to_string(),
kind: MagicKind::Shell, kind: IpyEscapeKind::Shell,
}, },
Tok::Newline, Tok::Newline,
] ]
@ -1440,7 +1443,7 @@ mod tests {
} }
#[test] #[test]
fn test_jupyter_magic_help_end() { fn test_ipython_help_end_escape_command() {
let source = r" let source = r"
?foo? ?foo?
?? foo? ?? foo?
@ -1465,84 +1468,84 @@ mod tests {
assert_eq!( assert_eq!(
tokens, tokens,
[ [
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: " foo ?".to_string(), value: " foo ?".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo???".to_string(), value: "foo???".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "?foo???".to_string(), value: "?foo???".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo".to_string(), value: "foo".to_string(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: " ?".to_string(), value: " ?".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "??".to_string(), value: "??".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "%foo".to_string(), value: "%foo".to_string(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "%foo".to_string(), value: "%foo".to_string(),
kind: MagicKind::Help2, kind: IpyEscapeKind::Help2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "foo???".to_string(), value: "foo???".to_string(),
kind: MagicKind::Magic2, kind: IpyEscapeKind::Magic2,
}, },
Tok::Newline, Tok::Newline,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "pwd".to_string(), value: "pwd".to_string(),
kind: MagicKind::Help, kind: IpyEscapeKind::Help,
}, },
Tok::Newline, Tok::Newline,
] ]
@ -1550,7 +1553,7 @@ mod tests {
} }
#[test] #[test]
fn test_jupyter_magic_indentation() { fn test_ipython_escape_command_indentation() {
let source = r" let source = r"
if True: if True:
%matplotlib \ %matplotlib \
@ -1565,9 +1568,9 @@ if True:
Tok::Colon, Tok::Colon,
Tok::Newline, Tok::Newline,
Tok::Indent, Tok::Indent,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "matplotlib --inline".to_string(), value: "matplotlib --inline".to_string(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
Tok::Dedent, Tok::Dedent,
@ -1576,7 +1579,7 @@ if True:
} }
#[test] #[test]
fn test_jupyter_magic_assignment() { fn test_ipython_escape_command_assignment() {
let source = r" let source = r"
pwd = !pwd pwd = !pwd
foo = %timeit a = b foo = %timeit a = b
@ -1592,54 +1595,54 @@ baz = %matplotlib \
name: "pwd".to_string() name: "pwd".to_string()
}, },
Tok::Equal, Tok::Equal,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "pwd".to_string(), value: "pwd".to_string(),
kind: MagicKind::Shell, kind: IpyEscapeKind::Shell,
}, },
Tok::Newline, Tok::Newline,
Tok::Name { Tok::Name {
name: "foo".to_string() name: "foo".to_string()
}, },
Tok::Equal, Tok::Equal,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "timeit a = b".to_string(), value: "timeit a = b".to_string(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
Tok::Name { Tok::Name {
name: "bar".to_string() name: "bar".to_string()
}, },
Tok::Equal, Tok::Equal,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "timeit a % 3".to_string(), value: "timeit a % 3".to_string(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
Tok::Name { Tok::Name {
name: "baz".to_string() name: "baz".to_string()
}, },
Tok::Equal, Tok::Equal,
Tok::MagicCommand { Tok::IpyEscapeCommand {
value: "matplotlib inline".to_string(), value: "matplotlib inline".to_string(),
kind: MagicKind::Magic, kind: IpyEscapeKind::Magic,
}, },
Tok::Newline, Tok::Newline,
] ]
); );
} }
fn assert_no_jupyter_magic(tokens: &[Tok]) { fn assert_no_ipython_escape_command(tokens: &[Tok]) {
for tok in tokens { for tok in tokens {
if let Tok::MagicCommand { .. } = tok { if let Tok::IpyEscapeCommand { .. } = tok {
panic!("Unexpected magic command token: {tok:?}") panic!("Unexpected escape command token: {tok:?}")
} }
} }
} }
#[test] #[test]
fn test_jupyter_magic_not_an_assignment() { fn test_ipython_escape_command_not_an_assignment() {
let source = r" let source = r"
# Other magic kinds are not valid here (can't test `foo = ?str` because '?' is not a valid token) # Other escape kinds are not valid here (can't test `foo = ?str` because '?' is not a valid token)
foo = /func foo = /func
foo = ;func foo = ;func
foo = ,func foo = ,func
@ -1650,7 +1653,7 @@ def f(arg=%timeit a = b):
pass" pass"
.trim(); .trim();
let tokens = lex_jupyter_source(source); let tokens = lex_jupyter_source(source);
assert_no_jupyter_magic(&tokens); assert_no_ipython_escape_command(&tokens);
} }
#[test] #[test]

View file

@ -117,7 +117,7 @@ pub fn parse_expression_starts_at(
/// ///
/// This function is the most general function to parse Python code. Based on the [`Mode`] supplied, /// This function is the most general function to parse Python code. Based on the [`Mode`] supplied,
/// it can be used to parse a single expression, a full Python program, an interactive expression /// it can be used to parse a single expression, a full Python program, an interactive expression
/// or a Python program containing Jupyter magics. /// or a Python program containing IPython escape commands.
/// ///
/// # Example /// # Example
/// ///
@ -146,7 +146,7 @@ pub fn parse_expression_starts_at(
/// assert!(program.is_ok()); /// assert!(program.is_ok());
/// ``` /// ```
/// ///
/// Additionally, we can parse a Python program containing Jupyter magics: /// Additionally, we can parse a Python program containing IPython escapes:
/// ///
/// ``` /// ```
/// use ruff_python_parser::{Mode, parse}; /// use ruff_python_parser::{Mode, parse};
@ -1122,7 +1122,7 @@ class Abcd:
} }
#[test] #[test]
fn test_jupyter_magic() { fn test_ipython_escape_commands() {
let parse_ast = parse( let parse_ast = parse(
r#" r#"
# Normal Python code # Normal Python code
@ -1169,7 +1169,7 @@ def foo():
;foo 1 2 ;foo 1 2
,foo 1 2 ,foo 1 2
# Indented magic # Indented escape commands
for a in range(5): for a in range(5):
!ls !ls
@ -1199,7 +1199,7 @@ foo.bar[0].baz[2].egg??
} }
#[test] #[test]
fn test_jupyter_magic_parse_error() { fn test_ipython_escape_command_parse_error() {
let source = r#" let source = r#"
a = 1 a = 1
%timeit a == 1 %timeit a == 1
@ -1209,7 +1209,7 @@ a = 1
let parse_err = parse_tokens(lxr, Mode::Module, "<test>").unwrap_err(); let parse_err = parse_tokens(lxr, Mode::Module, "<test>").unwrap_err();
assert_eq!( assert_eq!(
parse_err.to_string(), parse_err.to_string(),
"line magics are only allowed in Jupyter mode at byte offset 6".to_string() "IPython escape commands are only allowed in Jupyter mode at byte offset 6".to_string()
); );
} }
} }

View file

@ -5,7 +5,7 @@
use num_bigint::BigInt; use num_bigint::BigInt;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use ruff_python_ast::{self as ast, Ranged, MagicKind}; use ruff_python_ast::{self as ast, Ranged, IpyEscapeKind};
use crate::{ use crate::{
Mode, Mode,
lexer::{LexicalError, LexicalErrorType}, lexer::{LexicalError, LexicalErrorType},
@ -89,8 +89,8 @@ SmallStatement: ast::Stmt = {
NonlocalStatement, NonlocalStatement,
AssertStatement, AssertStatement,
TypeAliasStatement, TypeAliasStatement,
LineMagicStatement, IpyEscapeCommandStatement,
HelpEndLineMagic, IpyHelpEndEscapeCommandStatement,
}; };
PassStatement: ast::Stmt = { PassStatement: ast::Stmt = {
@ -155,7 +155,7 @@ ExpressionStatement: ast::Stmt = {
AssignSuffix: ast::Expr = { AssignSuffix: ast::Expr = {
"=" <e:TestListOrYieldExpr> => e, "=" <e:TestListOrYieldExpr> => e,
"=" <e:LineMagicExpr> => e "=" <e:IpyEscapeCommandExpr> => e
}; };
TestListOrYieldExpr: ast::Expr = { TestListOrYieldExpr: ast::Expr = {
@ -323,52 +323,52 @@ AssertStatement: ast::Stmt = {
}, },
}; };
LineMagicStatement: ast::Stmt = { IpyEscapeCommandStatement: ast::Stmt = {
<location:@L> <m:line_magic> <end_location:@R> =>? { <location:@L> <c:ipy_escape_command> <end_location:@R> =>? {
if mode == Mode::Jupyter { if mode == Mode::Jupyter {
Ok(ast::Stmt::LineMagic( Ok(ast::Stmt::IpyEscapeCommand(
ast::StmtLineMagic { ast::StmtIpyEscapeCommand {
kind: m.0, kind: c.0,
value: m.1, value: c.1,
range: (location..end_location).into() range: (location..end_location).into()
} }
)) ))
} else { } else {
Err(LexicalError { Err(LexicalError {
error: LexicalErrorType::OtherError("line magics are only allowed in Jupyter mode".to_string()), error: LexicalErrorType::OtherError("IPython escape commands are only allowed in Jupyter mode".to_string()),
location, location,
})? })?
} }
} }
} }
LineMagicExpr: ast::Expr = { IpyEscapeCommandExpr: ast::Expr = {
<location:@L> <m:line_magic> <end_location:@R> =>? { <location:@L> <c:ipy_escape_command> <end_location:@R> =>? {
if mode == Mode::Jupyter { if mode == Mode::Jupyter {
// This should never occur as the lexer won't allow it. // This should never occur as the lexer won't allow it.
if !matches!(m.0, MagicKind::Magic | MagicKind::Shell) { if !matches!(c.0, IpyEscapeKind::Magic | IpyEscapeKind::Shell) {
return Err(LexicalError { return Err(LexicalError {
error: LexicalErrorType::OtherError("expr line magics are only allowed for % and !".to_string()), error: LexicalErrorType::OtherError("IPython escape command expr is only allowed for % and !".to_string()),
location, location,
})?; })?;
} }
Ok(ast::Expr::LineMagic( Ok(ast::Expr::IpyEscapeCommand(
ast::ExprLineMagic { ast::ExprIpyEscapeCommand {
kind: m.0, kind: c.0,
value: m.1, value: c.1,
range: (location..end_location).into() range: (location..end_location).into()
} }
)) ))
} else { } else {
Err(LexicalError { Err(LexicalError {
error: LexicalErrorType::OtherError("line magics are only allowed in Jupyter mode".to_string()), error: LexicalErrorType::OtherError("IPython escape commands are only allowed in Jupyter mode".to_string()),
location, location,
})? })?
} }
} }
} }
HelpEndLineMagic: ast::Stmt = { IpyHelpEndEscapeCommandStatement: ast::Stmt = {
// We are permissive than the original implementation because we would allow whitespace // We are permissive than the original implementation because we would allow whitespace
// between the expression and the suffix while the IPython implementation doesn't allow it. // between the expression and the suffix while the IPython implementation doesn't allow it.
// For example, `foo ?` would be valid in our case but invalid from IPython. // For example, `foo ?` would be valid in our case but invalid from IPython.
@ -404,7 +404,7 @@ HelpEndLineMagic: ast::Stmt = {
} }
Ok(()) Ok(())
} }
if mode != Mode::Jupyter { if mode != Mode::Jupyter {
return Err(ParseError::User { return Err(ParseError::User {
error: LexicalError { error: LexicalError {
@ -415,8 +415,8 @@ HelpEndLineMagic: ast::Stmt = {
} }
let kind = match suffix.len() { let kind = match suffix.len() {
1 => MagicKind::Help, 1 => IpyEscapeKind::Help,
2 => MagicKind::Help2, 2 => IpyEscapeKind::Help2,
_ => { _ => {
return Err(ParseError::User { return Err(ParseError::User {
error: LexicalError { error: LexicalError {
@ -429,9 +429,9 @@ HelpEndLineMagic: ast::Stmt = {
let mut value = String::new(); let mut value = String::new();
unparse_expr(&e, &mut value)?; unparse_expr(&e, &mut value)?;
Ok(ast::Stmt::LineMagic( Ok(ast::Stmt::IpyEscapeCommand(
ast::StmtLineMagic { ast::StmtIpyEscapeCommand {
kind, kind,
value, value,
range: (location..end_location).into() range: (location..end_location).into()
@ -1900,8 +1900,8 @@ extern {
triple_quoted: <bool> triple_quoted: <bool>
}, },
name => token::Tok::Name { name: <String> }, name => token::Tok::Name { name: <String> },
line_magic => token::Tok::MagicCommand { ipy_escape_command => token::Tok::IpyEscapeCommand {
kind: <MagicKind>, kind: <IpyEscapeKind>,
value: <String> value: <String>
}, },
"\n" => token::Tok::Newline, "\n" => token::Tok::Newline,

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ expression: parse_ast
--- ---
Module( Module(
ModModule { ModModule {
range: 0..919, range: 0..929,
body: [ body: [
Expr( Expr(
StmtExpr { StmtExpr {
@ -31,92 +31,92 @@ Module(
), ),
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 66..73, range: 66..73,
kind: Help2, kind: Help2,
value: "a.foo", value: "a.foo",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 74..80, range: 74..80,
kind: Help, kind: Help,
value: "a.foo", value: "a.foo",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 81..88, range: 81..88,
kind: Help, kind: Help,
value: "a.foo", value: "a.foo",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 89..100, range: 89..100,
kind: Help2, kind: Help2,
value: "a.foo()", value: "a.foo()",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 115..128, range: 115..128,
kind: Magic, kind: Magic,
value: "timeit a = b", value: "timeit a = b",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 129..147, range: 129..147,
kind: Magic, kind: Magic,
value: "timeit foo(b) % 3", value: "timeit foo(b) % 3",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 148..176, range: 148..176,
kind: Magic, kind: Magic,
value: "alias showPath pwd && ls -a", value: "alias showPath pwd && ls -a",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 177..205, range: 177..205,
kind: Magic, kind: Magic,
value: "timeit a = foo(b); b = 2", value: "timeit a = foo(b); b = 2",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 206..226, range: 206..226,
kind: Magic, kind: Magic,
value: "matplotlib --inline", value: "matplotlib --inline",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 227..253, range: 227..253,
kind: Magic, kind: Magic,
value: "matplotlib --inline", value: "matplotlib --inline",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 277..309, range: 277..309,
kind: Shell, kind: Shell,
value: "pwd && ls -a | sed 's/^/\\ /'", value: "pwd && ls -a | sed 's/^/\\ /'",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 310..347, range: 310..347,
kind: Shell, kind: Shell,
value: "pwd && ls -a | sed 's/^/\\\\ /'", value: "pwd && ls -a | sed 's/^/\\\\ /'",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 348..393, range: 348..393,
kind: ShCap, kind: ShCap,
value: "cd /Users/foo/Library/Application\\ Support/", value: "cd /Users/foo/Library/Application\\ Support/",
@ -176,22 +176,22 @@ Module(
], ],
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 656..664, range: 656..664,
kind: Paren, kind: Paren,
value: "foo 1 2", value: "foo 1 2",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 665..673, range: 665..673,
kind: Quote2, kind: Quote2,
value: "foo 1 2", value: "foo 1 2",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 674..682, range: 674..682,
kind: Quote, kind: Quote,
value: "foo 1 2", value: "foo 1 2",
@ -199,31 +199,31 @@ Module(
), ),
For( For(
StmtFor { StmtFor {
range: 701..727, range: 711..737,
is_async: false, is_async: false,
target: Name( target: Name(
ExprName { ExprName {
range: 705..706, range: 715..716,
id: "a", id: "a",
ctx: Store, ctx: Store,
}, },
), ),
iter: Call( iter: Call(
ExprCall { ExprCall {
range: 710..718, range: 720..728,
func: Name( func: Name(
ExprName { ExprName {
range: 710..715, range: 720..725,
id: "range", id: "range",
ctx: Load, ctx: Load,
}, },
), ),
arguments: Arguments { arguments: Arguments {
range: 715..718, range: 725..728,
args: [ args: [
Constant( Constant(
ExprConstant { ExprConstant {
range: 716..717, range: 726..727,
value: Int( value: Int(
5, 5,
), ),
@ -236,9 +236,9 @@ Module(
}, },
), ),
body: [ body: [
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 724..727, range: 734..737,
kind: Shell, kind: Shell,
value: "ls", value: "ls",
}, },
@ -249,19 +249,19 @@ Module(
), ),
Assign( Assign(
StmtAssign { StmtAssign {
range: 729..738, range: 739..748,
targets: [ targets: [
Name( Name(
ExprName { ExprName {
range: 729..731, range: 739..741,
id: "p1", id: "p1",
ctx: Store, ctx: Store,
}, },
), ),
], ],
value: LineMagic( value: IpyEscapeCommand(
ExprLineMagic { ExprIpyEscapeCommand {
range: 734..738, range: 744..748,
kind: Shell, kind: Shell,
value: "pwd", value: "pwd",
}, },
@ -270,25 +270,25 @@ Module(
), ),
AnnAssign( AnnAssign(
StmtAnnAssign { StmtAnnAssign {
range: 739..753, range: 749..763,
target: Name( target: Name(
ExprName { ExprName {
range: 739..741, range: 749..751,
id: "p2", id: "p2",
ctx: Store, ctx: Store,
}, },
), ),
annotation: Name( annotation: Name(
ExprName { ExprName {
range: 743..746, range: 753..756,
id: "str", id: "str",
ctx: Load, ctx: Load,
}, },
), ),
value: Some( value: Some(
LineMagic( IpyEscapeCommand(
ExprLineMagic { ExprIpyEscapeCommand {
range: 749..753, range: 759..763,
kind: Shell, kind: Shell,
value: "pwd", value: "pwd",
}, },
@ -299,98 +299,98 @@ Module(
), ),
Assign( Assign(
StmtAssign { StmtAssign {
range: 754..774, range: 764..784,
targets: [ targets: [
Name( Name(
ExprName { ExprName {
range: 754..757, range: 764..767,
id: "foo", id: "foo",
ctx: Store, ctx: Store,
}, },
), ),
], ],
value: LineMagic( value: IpyEscapeCommand(
ExprLineMagic { ExprIpyEscapeCommand {
range: 760..774, range: 770..784,
kind: Magic, kind: Magic,
value: "foo bar", value: "foo bar",
}, },
), ),
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 776..781, range: 786..791,
kind: Magic, kind: Magic,
value: " foo", value: " foo",
}, },
), ),
Assign( Assign(
StmtAssign { StmtAssign {
range: 782..803, range: 792..813,
targets: [ targets: [
Name( Name(
ExprName { ExprName {
range: 782..785, range: 792..795,
id: "foo", id: "foo",
ctx: Store, ctx: Store,
}, },
), ),
], ],
value: LineMagic( value: IpyEscapeCommand(
ExprLineMagic { ExprIpyEscapeCommand {
range: 788..803, range: 798..813,
kind: Magic, kind: Magic,
value: "foo # comment", value: "foo # comment",
}, },
), ),
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 828..832, range: 838..842,
kind: Help, kind: Help,
value: "foo", value: "foo",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 833..842, range: 843..852,
kind: Help2, kind: Help2,
value: "foo.bar", value: "foo.bar",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 843..855, range: 853..865,
kind: Help, kind: Help,
value: "foo.bar.baz", value: "foo.bar.baz",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 856..864, range: 866..874,
kind: Help2, kind: Help2,
value: "foo[0]", value: "foo[0]",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 865..875, range: 875..885,
kind: Help, kind: Help,
value: "foo[0][1]", value: "foo[0][1]",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 876..895, range: 886..905,
kind: Help2, kind: Help2,
value: "foo.bar[0].baz[1]", value: "foo.bar[0].baz[1]",
}, },
), ),
LineMagic( IpyEscapeCommand(
StmtLineMagic { StmtIpyEscapeCommand {
range: 896..919, range: 906..929,
kind: Help2, kind: Help2,
value: "foo.bar[0].baz[2].egg", value: "foo.bar[0].baz[2].egg",
}, },

View file

@ -6,7 +6,7 @@
//! [CPython source]: https://github.com/python/cpython/blob/dfc2e065a2e71011017077e549cd2f9bf4944c54/Include/internal/pycore_token.h; //! [CPython source]: https://github.com/python/cpython/blob/dfc2e065a2e71011017077e549cd2f9bf4944c54/Include/internal/pycore_token.h;
use crate::Mode; use crate::Mode;
use num_bigint::BigInt; use num_bigint::BigInt;
use ruff_python_ast::MagicKind; use ruff_python_ast::IpyEscapeKind;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use std::fmt; use std::fmt;
@ -44,13 +44,13 @@ pub enum Tok {
/// Whether the string is triple quoted. /// Whether the string is triple quoted.
triple_quoted: bool, triple_quoted: bool,
}, },
/// Token value for a Jupyter magic commands. These are filtered out of the token stream /// Token value for IPython escape commands. These are recognized by the lexer
/// prior to parsing when the mode is [`Mode::Jupyter`]. /// only when the mode is [`Mode::Jupyter`].
MagicCommand { IpyEscapeCommand {
/// The magic command value. /// The magic command value.
value: String, value: String,
/// The kind of magic command. /// The kind of magic command.
kind: MagicKind, kind: IpyEscapeKind,
}, },
/// Token value for a comment. These are filtered out of the token stream prior to parsing. /// Token value for a comment. These are filtered out of the token stream prior to parsing.
Comment(String), Comment(String),
@ -234,7 +234,7 @@ impl fmt::Display for Tok {
let quotes = "\"".repeat(if *triple_quoted { 3 } else { 1 }); let quotes = "\"".repeat(if *triple_quoted { 3 } else { 1 });
write!(f, "{kind}{quotes}{value}{quotes}") write!(f, "{kind}{quotes}{value}{quotes}")
} }
MagicCommand { kind, value } => write!(f, "{kind}{value}"), IpyEscapeCommand { kind, value } => write!(f, "{kind}{value}"),
Newline => f.write_str("Newline"), Newline => f.write_str("Newline"),
NonLogicalNewline => f.write_str("NonLogicalNewline"), NonLogicalNewline => f.write_str("NonLogicalNewline"),
Indent => f.write_str("Indent"), Indent => f.write_str("Indent"),
@ -450,8 +450,8 @@ pub enum TokenKind {
Complex, Complex,
/// Token value for a string. /// Token value for a string.
String, String,
/// Token value for a Jupyter magic command. /// Token value for a IPython escape command.
MagicCommand, EscapeCommand,
/// Token value for a comment. These are filtered out of the token stream prior to parsing. /// Token value for a comment. These are filtered out of the token stream prior to parsing.
Comment, Comment,
/// Token value for a newline. /// Token value for a newline.
@ -781,7 +781,7 @@ impl TokenKind {
Tok::Float { .. } => TokenKind::Float, Tok::Float { .. } => TokenKind::Float,
Tok::Complex { .. } => TokenKind::Complex, Tok::Complex { .. } => TokenKind::Complex,
Tok::String { .. } => TokenKind::String, Tok::String { .. } => TokenKind::String,
Tok::MagicCommand { .. } => TokenKind::MagicCommand, Tok::IpyEscapeCommand { .. } => TokenKind::EscapeCommand,
Tok::Comment(_) => TokenKind::Comment, Tok::Comment(_) => TokenKind::Comment,
Tok::Newline => TokenKind::Newline, Tok::Newline => TokenKind::Newline,
Tok::NonLogicalNewline => TokenKind::NonLogicalNewline, Tok::NonLogicalNewline => TokenKind::NonLogicalNewline,