Jelajahi Sumber

Mimic 'Mode' in gci

Chester Liu 4 tahun lalu
induk
melakukan
00f97a9738
4 mengubah file dengan 74 tambahan dan 1 penghapusan
  1. 13 0
      src/fs/fields.rs
  2. 17 0
      src/fs/file.rs
  3. 39 1
      src/output/render/permissions.rs
  4. 5 0
      src/output/table.rs

+ 13 - 0
src/fs/fields.rs

@@ -82,6 +82,17 @@ pub struct Permissions {
     pub setuid:         bool,
 }
 
+/// The file's FileAttributes field, available only on Windows.
+#[derive(Copy, Clone)]
+pub struct Attributes {
+    pub archive:         bool,
+    pub directory:       bool,
+    pub readonly:        bool,
+    pub hidden:          bool,
+    pub system:          bool,
+    pub reparse_point:   bool,
+}
+
 /// The three pieces of information that are displayed as a single column in
 /// the details view. These values are fused together to make the output a
 /// little more compressed.
@@ -90,6 +101,8 @@ pub struct PermissionsPlus {
     pub file_type:   Type,
     #[cfg(unix)]
     pub permissions: Permissions,
+    #[cfg(windows)]
+    pub attributes:  Attributes,
     pub xattrs:      bool,
 }
 

+ 17 - 0
src/fs/file.rs

@@ -3,6 +3,8 @@
 use std::io;
 #[cfg(unix)]
 use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
+#[cfg(windows)]
+use std::os::windows::fs::MetadataExt;
 use std::path::{Path, PathBuf};
 use std::time::{Duration, SystemTime, UNIX_EPOCH};
 
@@ -463,6 +465,21 @@ impl<'dir> File<'dir> {
         }
     }
 
+    #[cfg(windows)]
+    pub fn attributes(&self) -> f::Attributes {
+        let bits = self.metadata.file_attributes();
+        let has_bit = |bit| bits & bit == bit;
+
+        f::Attributes {
+            directory:      has_bit(0x10),
+            archive:        has_bit(0x20),
+            readonly:       has_bit(0x1),
+            hidden:         has_bit(0x2),
+            system:         has_bit(0x4),
+            reparse_point:  has_bit(0x400),
+        }
+    }
+
     /// Whether this file’s extension is any of the strings that get passed in.
     ///
     /// This will always return `false` if the file has no extension.

+ 39 - 1
src/output/render/permissions.rs

@@ -6,9 +6,9 @@ use crate::output::render::FiletypeColours;
 
 
 impl f::PermissionsPlus {
+    #[cfg(unix)]
     pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
         let mut chars = vec![ self.file_type.render(colours) ];
-        #[cfg(unix)]
         chars.extend(self.permissions.render(colours, self.file_type.is_regular_file()));
 
         if self.xattrs {
@@ -23,6 +23,17 @@ impl f::PermissionsPlus {
             contents: chars.into(),
         }
     }
+
+    #[cfg(windows)]
+    pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
+        let mut chars = vec![ self.attributes.render_type(colours) ];
+        chars.extend(self.attributes.render(colours));
+
+        TextCell {
+            width:    DisplayWidth::from(chars.len()),
+            contents: chars.into(),
+        }
+    }
 }
 
 
@@ -77,6 +88,33 @@ impl f::Permissions {
     }
 }
 
+impl f::Attributes {
+    pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> Vec<ANSIString<'static>> {
+        let bit = |bit, chr: &'static str, style: Style| {
+            if bit { style.paint(chr) }
+              else { colours.dash().paint("-") }
+        };
+
+        vec![
+            bit(self.archive,   "a", colours.normal()),
+            bit(self.readonly,  "r", colours.user_read()),
+            bit(self.hidden,    "h", colours.special_user_file()),
+            bit(self.system,    "s", colours.special_other()),
+        ]
+    }
+
+    pub fn render_type<C: Colours+FiletypeColours>(&self, colours: &C) -> ANSIString<'static> {
+        if self.reparse_point {
+            return colours.pipe().paint("l")
+        }
+        else if self.directory {
+            return colours.directory().paint("d")
+        }
+        else {
+            return colours.dash().paint("-")
+        }
+    }
+}
 
 pub trait Colours {
     fn dash(&self) -> Style;

+ 5 - 0
src/output/table.rs

@@ -171,7 +171,10 @@ impl Column {
     /// to have a header row printed.
     pub fn header(self) -> &'static str {
         match self {
+            #[cfg(unix)]
             Self::Permissions   => "Permissions",
+            #[cfg(windows)]
+            Self::Permissions   => "Mode",
             Self::FileSize      => "Size",
             Self::Timestamp(t)  => t.header(),
             #[cfg(unix)]
@@ -422,6 +425,8 @@ impl<'a, 'f> Table<'a> {
             file_type: file.type_char(),
             #[cfg(unix)]
             permissions: file.permissions(),
+            #[cfg(windows)]
+            attributes: file.attributes(),
             xattrs,
         }
     }