Add support for Image targets in the intermediate step.
This commit is contained in:
		
							parent
							
								
									7c92b602bc
								
							
						
					
					
						commit
						eb18185131
					
				
							
								
								
									
										22
									
								
								org_test_documents/regular_link/image_links.org
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								org_test_documents/regular_link/image_links.org
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| [[file:image.svg]] | ||||
| 
 | ||||
| [[file:/image.svg]] | ||||
| 
 | ||||
| [[file:./image.svg]] | ||||
| 
 | ||||
| [[/image.svg]] | ||||
| 
 | ||||
| [[./image.svg]] | ||||
| 
 | ||||
| # Check capitalization of extension | ||||
| [[./image.SVG]] | ||||
| 
 | ||||
| # Check spaces in path | ||||
| [[./image and stuff.SVG]] | ||||
| 
 | ||||
| [[/ssh:admin@test.example:important/file.svg]] | ||||
| 
 | ||||
| [[file:/ssh:admin@test.example:important/file.svg]] | ||||
| 
 | ||||
| # Check multiple parts in the path | ||||
| [[file:/foo/bar/baz/image.svg]] | ||||
| @ -1,3 +1,7 @@ | ||||
| use std::borrow::Cow; | ||||
| use std::path::Path; | ||||
| 
 | ||||
| use organic::types::LinkType; | ||||
| use organic::types::StandardProperties; | ||||
| use url::Url; | ||||
| 
 | ||||
| @ -31,8 +35,11 @@ intermediate!( | ||||
|             ret | ||||
|         }; | ||||
|         let raw_link = original.get_raw_link(); | ||||
|         let target = | ||||
|             LinkTarget::from_string(intermediate_context.clone(), raw_link.clone().into_owned())?; | ||||
|         let target = LinkTarget::from_string( | ||||
|             intermediate_context.clone(), | ||||
|             raw_link.clone().into_owned(), | ||||
|             &original.link_type, | ||||
|         )?; | ||||
|         Ok(IRegularLink { | ||||
|             raw_link: raw_link.into_owned(), | ||||
|             children, | ||||
| @ -52,13 +59,28 @@ pub(crate) enum LinkTarget { | ||||
|     Target { | ||||
|         target_id: String, | ||||
|     }, | ||||
|     Image { | ||||
|         src: String, | ||||
|         alt: String, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| impl LinkTarget { | ||||
|     pub(crate) fn from_string( | ||||
|         intermediate_context: IntermediateContext<'_, '_>, | ||||
|         input: String, | ||||
|         link_type: &LinkType<'_>, | ||||
|     ) -> Result<LinkTarget, CustomError> { | ||||
|         // If link type is file and the path ends in .svg then make it an image target
 | ||||
|         if let LinkType::File = link_type | ||||
|             && input.to_ascii_lowercase().ends_with(".svg") | ||||
|         { | ||||
|             let src = Self::get_image_src(&input)?; | ||||
|             let alt = Self::get_image_alt(&input)?; | ||||
| 
 | ||||
|             return Ok(LinkTarget::Image { src, alt }); | ||||
|         }; | ||||
| 
 | ||||
|         let parsed = Url::parse(&input); | ||||
|         if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed { | ||||
|             let target_id = { | ||||
| @ -121,12 +143,64 @@ impl LinkTarget { | ||||
|                     .unwrap_or_default(), | ||||
|                 target_id | ||||
|             ))), | ||||
|             LinkTarget::Image { src, .. } => Ok(Some(src.clone())), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Get the value for the src attribute of the image.
 | ||||
|     fn get_image_src(input: &str) -> Result<String, CustomError> { | ||||
|         let input = if input.to_ascii_lowercase().starts_with("file:") { | ||||
|             Cow::Borrowed(&input[5..]) | ||||
|         } else { | ||||
|             Cow::Borrowed(input) | ||||
|         }; | ||||
|         let path = Path::new(input.as_ref()); | ||||
| 
 | ||||
|         if input.to_ascii_lowercase().starts_with("/ssh:") { | ||||
|             return Ok(format!("file:/{}", input)); | ||||
|         } | ||||
| 
 | ||||
|         if path.is_absolute() { | ||||
|             return Ok(format!("file://{}", input)); | ||||
|         } | ||||
|         return Ok(input.into_owned()); | ||||
|     } | ||||
| 
 | ||||
|     /// Get file name from the last segment of an image path.
 | ||||
|     fn get_image_alt(input: &str) -> Result<String, CustomError> { | ||||
|         let input = if input.to_ascii_lowercase().starts_with("file:") { | ||||
|             Cow::Borrowed(&input[5..]) | ||||
|         } else { | ||||
|             Cow::Borrowed(input) | ||||
|         }; | ||||
|         let path = Path::new(input.as_ref()); | ||||
|         match path | ||||
|             .components() | ||||
|             .last() | ||||
|             .ok_or("Images should have at least one component in their path.")? | ||||
|         { | ||||
|             std::path::Component::Prefix(_) => { | ||||
|                 // Prefix components only occur on windows
 | ||||
|                 panic!("Prefix components are not supporterd.") | ||||
|             } | ||||
|             std::path::Component::RootDir | ||||
|             | std::path::Component::CurDir | ||||
|             | std::path::Component::ParentDir => { | ||||
|                 return Err( | ||||
|                     "Final component of an image path should be a normal component.".into(), | ||||
|                 ); | ||||
|             } | ||||
|             std::path::Component::Normal(file_name) => Ok(file_name | ||||
|                 .to_str() | ||||
|                 .ok_or("Image link was not valid utf-8.")? | ||||
|                 .to_owned()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use std::borrow::Cow; | ||||
|     use std::sync::Arc; | ||||
|     use std::sync::Mutex; | ||||
| 
 | ||||
| @ -139,12 +213,78 @@ mod tests { | ||||
|         let registry = Registry::new(); | ||||
|         let registry = Arc::new(Mutex::new(registry)); | ||||
|         let intermediate_context = IntermediateContext::new(registry)?; | ||||
|         for inp in ["https://test.example/foo"] { | ||||
|         for (inp, typ) in [( | ||||
|             "https://test.example/foo", | ||||
|             LinkType::Protocol(Cow::from("https")), | ||||
|         )] { | ||||
|             assert_eq!( | ||||
|                 LinkTarget::from_string(intermediate_context.clone(), inp.to_owned())?, | ||||
|                 LinkTarget::from_string(intermediate_context.clone(), inp.to_owned(), &typ)?, | ||||
|                 LinkTarget::Raw(inp.to_owned()) | ||||
|             ); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn link_target_image() -> Result<(), CustomError> { | ||||
|         let registry = Registry::new(); | ||||
|         let registry = Arc::new(Mutex::new(registry)); | ||||
|         let intermediate_context = IntermediateContext::new(registry)?; | ||||
|         for (inp, typ, expected_src, expected_alt) in [ | ||||
|             ("file:image.svg", LinkType::File, "image.svg", "image.svg"), | ||||
|             ( | ||||
|                 "file:/image.svg", | ||||
|                 LinkType::File, | ||||
|                 "file:///image.svg", | ||||
|                 "image.svg", | ||||
|             ), | ||||
|             ( | ||||
|                 "file:./image.svg", | ||||
|                 LinkType::File, | ||||
|                 "./image.svg", | ||||
|                 "image.svg", | ||||
|             ), | ||||
|             ( | ||||
|                 "/image.svg", | ||||
|                 LinkType::File, | ||||
|                 "file:///image.svg", | ||||
|                 "image.svg", | ||||
|             ), | ||||
|             ("./image.svg", LinkType::File, "./image.svg", "image.svg"), | ||||
|             ("./image.SVG", LinkType::File, "./image.SVG", "image.SVG"), | ||||
|             ( | ||||
|                 "./image and stuff.SVG", | ||||
|                 LinkType::File, | ||||
|                 "./image and stuff.SVG", | ||||
|                 "image and stuff.SVG", | ||||
|             ), | ||||
|             ( | ||||
|                 "/ssh:admin@test.example:important/file.svg", | ||||
|                 LinkType::File, | ||||
|                 "file://ssh:admin@test.example:important/file.svg", | ||||
|                 "file.svg", | ||||
|             ), | ||||
|             ( | ||||
|                 "file:/ssh:admin@test.example:important/file.svg", | ||||
|                 LinkType::File, | ||||
|                 "file://ssh:admin@test.example:important/file.svg", | ||||
|                 "file.svg", | ||||
|             ), | ||||
|             ( | ||||
|                 "file:/foo/bar/baz/image.svg", | ||||
|                 LinkType::File, | ||||
|                 "file:///foo/bar/baz/image.svg", | ||||
|                 "image.svg", | ||||
|             ), | ||||
|         ] { | ||||
|             assert_eq!( | ||||
|                 LinkTarget::from_string(intermediate_context.clone(), inp.to_owned(), &typ)?, | ||||
|                 LinkTarget::Image { | ||||
|                     src: expected_src.to_owned(), | ||||
|                     alt: expected_alt.to_owned() | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander