From f9b2d73dd4290104413481801bd854237b028cc8 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Wed, 8 May 2024 18:46:39 +0800 Subject: [PATCH] feat: Link::description & Link::description_raw --- src/ast/link.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/ast/link.rs b/src/ast/link.rs index eddb2ef..48f55d2 100644 --- a/src/ast/link.rs +++ b/src/ast/link.rs @@ -1,7 +1,7 @@ use rowan::ast::{support, AstNode}; use super::{AffiliatedKeyword, Link, Paragraph, Token}; -use crate::syntax::SyntaxKind; +use crate::{syntax::SyntaxKind, SyntaxElement}; impl Link { /// Returns link destination @@ -35,9 +35,59 @@ impl Link { /// assert!(!link.has_description()); /// let link = Org::parse("[[https://google.com][Google]]").first_node::().unwrap(); /// assert!(link.has_description()); + /// let link = Org::parse("[[https://example.com][*abc* /abc/]]").first_node::().unwrap(); + /// assert!(link.has_description()); /// ``` pub fn has_description(&self) -> bool { - support::token(self.syntax(), SyntaxKind::TEXT).is_some() + self.syntax() + .children_with_tokens() + .any(|e| e.kind() == SyntaxKind::L_BRACKET) + } + + /// Returns parsed description + /// + /// Returns empty iterator if this link doesn't contain description + /// + /// ```rust + /// use orgize::{Org, ast::Link, SyntaxKind}; + /// + /// let link = Org::parse("[[https://google.com]]").first_node::().unwrap(); + /// assert_eq!(link.description().count(), 0); + /// + /// let link = Org::parse("[[https://google.com][Google]]").first_node::().unwrap(); + /// let description = link.description().collect::>(); + /// assert_eq!((description[0].kind(), description[0].to_string()), (SyntaxKind::TEXT, "Google".into())); + /// + /// let link = Org::parse("[[https://example.com][*abc* /abc/]]").first_node::().unwrap(); + /// let description = link.description().collect::>(); + /// assert_eq!((description[0].kind(), description[0].to_string()), (SyntaxKind::BOLD, "*abc*".into())); + /// assert_eq!((description[2].kind(), description[2].to_string()), (SyntaxKind::ITALIC, "/abc/".into())); + /// ``` + pub fn description(&self) -> impl Iterator { + self.syntax() + .children_with_tokens() + .skip_while(|e| e.kind() != SyntaxKind::L_BRACKET) + .skip(1) + .take_while(|e| e.kind() != SyntaxKind::R_BRACKET2) + } + + /// Returns description raw string + /// + /// Returns empty string if this link doesn't contain description + /// + /// ```rust + /// use orgize::{Org, ast::Link}; + /// + /// let link = Org::parse("[[https://google.com]]").first_node::().unwrap(); + /// assert_eq!(link.description_raw(), ""); + /// let link = Org::parse("[[https://google.com][Google]]").first_node::().unwrap(); + /// assert_eq!(link.description_raw(), "Google"); + /// let link = Org::parse("[[https://example.com][*abc* /abc/]]").first_node::().unwrap(); + /// assert_eq!(link.description_raw(), "*abc* /abc/"); + /// ``` + pub fn description_raw(&self) -> String { + self.description() + .fold(String::new(), |acc, e| acc + &e.to_string()) } /// Returns `true` if link is an image link