/crates/icon/src/lib.rs

https://github.com/liuchengxu/vim-clap · Rust · 144 lines · 112 code · 20 blank · 12 comment · 7 complexity · e8b7c688c3c7fdf20578f67dcb647c79 MD5 · raw file

  1. mod constants;
  2. pub use constants::*;
  3. use std::path::Path;
  4. use structopt::clap::arg_enum;
  5. pub const DEFAULT_ICON: char = '';
  6. pub const FOLDER_ICON: char = '';
  7. pub const DEFAULT_FILER_ICON: char = '';
  8. // Each added icon length is 4 bytes.
  9. pub const ICON_LEN: usize = 4;
  10. /// The type used to represent icons.
  11. ///
  12. /// This could be changed into different type later,
  13. /// so functions take and return this type, not `char` or `&str` directly.
  14. type Icon = char;
  15. /// Return appropriate icon for the path. If no icon matched, return the specified default one.
  16. ///
  17. /// Try matching the exactmatch map against the file name, and then the extension map.
  18. #[inline]
  19. pub fn get_icon_or(path: &Path, default: Icon) -> Icon {
  20. path.file_name()
  21. .and_then(std::ffi::OsStr::to_str)
  22. .and_then(|filename| {
  23. bsearch_icon_table(&filename.to_lowercase().as_str(), EXACTMATCH_ICON_TABLE)
  24. .map(|idx| EXACTMATCH_ICON_TABLE[idx].1)
  25. })
  26. .unwrap_or_else(|| {
  27. path.extension()
  28. .and_then(std::ffi::OsStr::to_str)
  29. .and_then(|ext| {
  30. bsearch_icon_table(ext, EXTENSION_ICON_TABLE)
  31. .map(|idx| EXTENSION_ICON_TABLE[idx].1)
  32. })
  33. .unwrap_or(default)
  34. })
  35. }
  36. fn icon_for(line: &str) -> Icon {
  37. let path = Path::new(line);
  38. get_icon_or(&path, DEFAULT_ICON)
  39. }
  40. pub fn prepend_icon(line: &str) -> String {
  41. format!("{} {}", icon_for(line), line)
  42. }
  43. #[inline]
  44. pub fn icon_for_filer(path: &Path) -> Icon {
  45. if path.is_dir() {
  46. FOLDER_ICON
  47. } else {
  48. get_icon_or(path, DEFAULT_FILER_ICON)
  49. }
  50. }
  51. pub fn prepend_filer_icon(path: &Path, line: &str) -> String {
  52. format!("{} {}", icon_for_filer(path), line)
  53. }
  54. fn get_tagkind_icon(line: &str) -> Icon {
  55. pattern::extract_proj_tags_kind(line)
  56. .and_then(|kind| {
  57. bsearch_icon_table(kind, TAGKIND_ICON_TABLE).map(|idx| TAGKIND_ICON_TABLE[idx].1)
  58. })
  59. .unwrap_or(DEFAULT_ICON)
  60. }
  61. #[inline]
  62. fn grep_icon_for(line: &str) -> Icon {
  63. pattern::extract_fpath_from_grep_line(line)
  64. .map(|fpath| icon_for(fpath))
  65. .unwrap_or(DEFAULT_ICON)
  66. }
  67. /// Prepend an icon to the output line of ripgrep.
  68. pub fn prepend_grep_icon(line: &str) -> String {
  69. format!("{} {}", grep_icon_for(line), line)
  70. }
  71. arg_enum! {
  72. /// Prepend an icon for various kind of output line.
  73. #[derive(Clone, Debug)]
  74. pub enum IconPainter {
  75. File,
  76. Grep,
  77. ProjTags
  78. }
  79. }
  80. impl IconPainter {
  81. /// Returns a `String` of raw str with icon added.
  82. pub fn paint(&self, raw_str: &str) -> String {
  83. match *self {
  84. Self::File => prepend_icon(raw_str),
  85. Self::Grep => prepend_grep_icon(raw_str),
  86. Self::ProjTags => format!("{} {}", get_tagkind_icon(raw_str), raw_str),
  87. }
  88. }
  89. /// Returns appropriate icon for the given text.
  90. pub fn get_icon(&self, text: &str) -> Icon {
  91. match *self {
  92. Self::File => icon_for(text),
  93. Self::Grep => grep_icon_for(text),
  94. Self::ProjTags => get_tagkind_icon(text),
  95. }
  96. }
  97. }
  98. #[cfg(test)]
  99. mod tests {
  100. use super::*;
  101. #[test]
  102. fn test_trim_trailing() {
  103. let empty_iconized_line = " ";
  104. assert_eq!(empty_iconized_line.len(), 4);
  105. assert!(empty_iconized_line.chars().next().unwrap() == DEFAULT_ICON);
  106. }
  107. #[test]
  108. fn test_icon_length() {
  109. for table in [EXTENSION_ICON_TABLE, EXACTMATCH_ICON_TABLE].iter() {
  110. for (_, i) in table.iter() {
  111. let icon = format!("{} ", i);
  112. assert_eq!(icon.len(), 4);
  113. }
  114. }
  115. }
  116. #[test]
  117. fn test_tagkind_icon() {
  118. let line = r#"Blines:19 [implementation@crates/maple_cli/src/cmd/blines.rs] impl Blines {"#;
  119. let icon_for = |kind: &str| {
  120. bsearch_icon_table(kind, TAGKIND_ICON_TABLE).map(|idx| TAGKIND_ICON_TABLE[idx].1)
  121. };
  122. assert_eq!(icon_for("implementation").unwrap(), get_tagkind_icon(line));
  123. }
  124. }