permissions.rs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. use std::iter;
  2. use ansi_term::{ANSIString, Style};
  3. use crate::fs::fields as f;
  4. use crate::output::cell::{TextCell, DisplayWidth};
  5. use crate::output::render::FiletypeColours;
  6. pub trait PermissionsPlusRender {
  7. fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell;
  8. }
  9. impl PermissionsPlusRender for Option<f::PermissionsPlus> {
  10. fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
  11. match self {
  12. Some(p) => {
  13. let mut chars = vec![ p.file_type.render(colours) ];
  14. let permissions = p.permissions;
  15. chars.extend(Some(permissions).render(colours, p.file_type.is_regular_file()));
  16. if p.xattrs {
  17. chars.push(colours.attribute().paint("@"));
  18. }
  19. // As these are all ASCII characters, we can guarantee that they’re
  20. // all going to be one character wide, and don’t need to compute the
  21. // cell’s display width.
  22. TextCell {
  23. width: DisplayWidth::from(chars.len()),
  24. contents: chars.into(),
  25. }
  26. },
  27. None => {
  28. let chars: Vec<_> = iter::repeat(colours.dash().paint("-")).take(10).collect();
  29. TextCell {
  30. width: DisplayWidth::from(chars.len()),
  31. contents: chars.into(),
  32. }
  33. }
  34. }
  35. }
  36. }
  37. pub trait RenderPermissions {
  38. fn render<C: Colours>(&self, colours: &C, is_regular_file: bool) -> Vec<ANSIString<'static>>;
  39. }
  40. impl RenderPermissions for Option<f::Permissions> {
  41. fn render<C: Colours>(&self, colours: &C, is_regular_file: bool) -> Vec<ANSIString<'static>> {
  42. match self {
  43. Some(p) => {
  44. let bit = |bit, chr: &'static str, style: Style| {
  45. if bit { style.paint(chr) }
  46. else { colours.dash().paint("-") }
  47. };
  48. vec![
  49. bit(p.user_read, "r", colours.user_read()),
  50. bit(p.user_write, "w", colours.user_write()),
  51. p.user_execute_bit(colours, is_regular_file),
  52. bit(p.group_read, "r", colours.group_read()),
  53. bit(p.group_write, "w", colours.group_write()),
  54. p.group_execute_bit(colours),
  55. bit(p.other_read, "r", colours.other_read()),
  56. bit(p.other_write, "w", colours.other_write()),
  57. p.other_execute_bit(colours)
  58. ]
  59. },
  60. None => {
  61. iter::repeat(colours.dash().paint("-")).take(9).collect()
  62. }
  63. }
  64. }
  65. }
  66. impl f::Permissions {
  67. fn user_execute_bit<C: Colours>(&self, colours: &C, is_regular_file: bool) -> ANSIString<'static> {
  68. match (self.user_execute, self.setuid, is_regular_file) {
  69. (false, false, _) => colours.dash().paint("-"),
  70. (true, false, false) => colours.user_execute_other().paint("x"),
  71. (true, false, true) => colours.user_execute_file().paint("x"),
  72. (false, true, _) => colours.special_other().paint("S"),
  73. (true, true, false) => colours.special_other().paint("s"),
  74. (true, true, true) => colours.special_user_file().paint("s"),
  75. }
  76. }
  77. fn group_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
  78. match (self.group_execute, self.setgid) {
  79. (false, false) => colours.dash().paint("-"),
  80. (true, false) => colours.group_execute().paint("x"),
  81. (false, true) => colours.special_other().paint("S"),
  82. (true, true) => colours.special_other().paint("s"),
  83. }
  84. }
  85. fn other_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
  86. match (self.other_execute, self.sticky) {
  87. (false, false) => colours.dash().paint("-"),
  88. (true, false) => colours.other_execute().paint("x"),
  89. (false, true) => colours.special_other().paint("T"),
  90. (true, true) => colours.special_other().paint("t"),
  91. }
  92. }
  93. }
  94. pub trait Colours {
  95. fn dash(&self) -> Style;
  96. fn user_read(&self) -> Style;
  97. fn user_write(&self) -> Style;
  98. fn user_execute_file(&self) -> Style;
  99. fn user_execute_other(&self) -> Style;
  100. fn group_read(&self) -> Style;
  101. fn group_write(&self) -> Style;
  102. fn group_execute(&self) -> Style;
  103. fn other_read(&self) -> Style;
  104. fn other_write(&self) -> Style;
  105. fn other_execute(&self) -> Style;
  106. fn special_user_file(&self) -> Style;
  107. fn special_other(&self) -> Style;
  108. fn attribute(&self) -> Style;
  109. }
  110. #[cfg(test)]
  111. #[allow(unused_results)]
  112. pub mod test {
  113. use super::{Colours, RenderPermissions};
  114. use crate::output::cell::TextCellContents;
  115. use crate::fs::fields as f;
  116. use ansi_term::Colour::*;
  117. use ansi_term::Style;
  118. struct TestColours;
  119. impl Colours for TestColours {
  120. fn dash(&self) -> Style { Fixed(11).normal() }
  121. fn user_read(&self) -> Style { Fixed(101).normal() }
  122. fn user_write(&self) -> Style { Fixed(102).normal() }
  123. fn user_execute_file(&self) -> Style { Fixed(103).normal() }
  124. fn user_execute_other(&self) -> Style { Fixed(113).normal() }
  125. fn group_read(&self) -> Style { Fixed(104).normal() }
  126. fn group_write(&self) -> Style { Fixed(105).normal() }
  127. fn group_execute(&self) -> Style { Fixed(106).normal() }
  128. fn other_read(&self) -> Style { Fixed(107).normal() }
  129. fn other_write(&self) -> Style { Fixed(108).normal() }
  130. fn other_execute(&self) -> Style { Fixed(109).normal() }
  131. fn special_user_file(&self) -> Style { Fixed(110).normal() }
  132. fn special_other(&self) -> Style { Fixed(111).normal() }
  133. fn attribute(&self) -> Style { Fixed(112).normal() }
  134. }
  135. #[test]
  136. fn negate() {
  137. let bits = Some(f::Permissions {
  138. user_read: false, user_write: false, user_execute: false, setuid: false,
  139. group_read: false, group_write: false, group_execute: false, setgid: false,
  140. other_read: false, other_write: false, other_execute: false, sticky: false,
  141. });
  142. let expected = TextCellContents::from(vec![
  143. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(11).paint("-"),
  144. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(11).paint("-"),
  145. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(11).paint("-"),
  146. ]);
  147. assert_eq!(expected, bits.render(&TestColours, false).into())
  148. }
  149. #[test]
  150. fn affirm() {
  151. let bits = Some(f::Permissions {
  152. user_read: true, user_write: true, user_execute: true, setuid: false,
  153. group_read: true, group_write: true, group_execute: true, setgid: false,
  154. other_read: true, other_write: true, other_execute: true, sticky: false,
  155. });
  156. let expected = TextCellContents::from(vec![
  157. Fixed(101).paint("r"), Fixed(102).paint("w"), Fixed(103).paint("x"),
  158. Fixed(104).paint("r"), Fixed(105).paint("w"), Fixed(106).paint("x"),
  159. Fixed(107).paint("r"), Fixed(108).paint("w"), Fixed(109).paint("x"),
  160. ]);
  161. assert_eq!(expected, bits.render(&TestColours, true).into())
  162. }
  163. #[test]
  164. fn specials() {
  165. let bits = Some(f::Permissions {
  166. user_read: false, user_write: false, user_execute: true, setuid: true,
  167. group_read: false, group_write: false, group_execute: true, setgid: true,
  168. other_read: false, other_write: false, other_execute: true, sticky: true,
  169. });
  170. let expected = TextCellContents::from(vec![
  171. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(110).paint("s"),
  172. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(111).paint("s"),
  173. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(111).paint("t"),
  174. ]);
  175. assert_eq!(expected, bits.render(&TestColours, true).into())
  176. }
  177. #[test]
  178. fn extra_specials() {
  179. let bits = Some(f::Permissions {
  180. user_read: false, user_write: false, user_execute: false, setuid: true,
  181. group_read: false, group_write: false, group_execute: false, setgid: true,
  182. other_read: false, other_write: false, other_execute: false, sticky: true,
  183. });
  184. let expected = TextCellContents::from(vec![
  185. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(111).paint("S"),
  186. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(111).paint("S"),
  187. Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(111).paint("T"),
  188. ]);
  189. assert_eq!(expected, bits.render(&TestColours, true).into())
  190. }
  191. }