diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | book/src/configuration.md | 3 | ||||
-rw-r--r-- | helix-term/src/commands/typed.rs | 2 | ||||
-rw-r--r-- | helix-term/src/ui/statusline.rs | 14 | ||||
-rw-r--r-- | helix-view/Cargo.toml | 1 | ||||
-rw-r--r-- | helix-view/src/document.rs | 35 | ||||
-rw-r--r-- | helix-view/src/editor.rs | 4 |
7 files changed, 58 insertions, 2 deletions
@@ -1392,6 +1392,7 @@ dependencies = [ "log", "once_cell", "parking_lot", + "rustix 0.38.4", "serde", "serde_json", "slotmap", diff --git a/book/src/configuration.md b/book/src/configuration.md index 4c152bf4..eb2cf473 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -89,7 +89,7 @@ The `[editor.statusline]` key takes the following sub-keys: | Key | Description | Default | | --- | --- | --- | -| `left` | A list of elements aligned to the left of the statusline | `["mode", "spinner", "file-name", "file-modification-indicator"]` | +| `left` | A list of elements aligned to the left of the statusline | `["mode", "spinner", "file-name", "read-only-indicator", "file-modification-indicator"]` | | `center` | A list of elements aligned to the middle of the statusline | `[]` | | `right` | A list of elements aligned to the right of the statusline | `["diagnostics", "selections", "register", "position", "file-encoding"]` | | `separator` | The character used to separate elements in the statusline | `"│"` | @@ -108,6 +108,7 @@ The following statusline elements can be configured: | `file-modification-indicator` | The indicator to show whether the file is modified (a `[+]` appears when there are unsaved changes) | | `file-encoding` | The encoding of the opened file if it differs from UTF-8 | | `file-line-ending` | The file line endings (CRLF or LF) | +| `read-only-indicator` | An indicator that shows `[readonly]` when a file cannot be written | | `total-line-numbers` | The total line numbers of the opened file | | `file-type` | The type of the opened file | | `diagnostics` | The number of warnings and/or errors | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 67640f79..5bb9c6c4 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -672,7 +672,7 @@ pub fn write_all_impl( } if doc.path().is_none() { if write_scratch { - errors.push("cannot write a buffer without a filename\n"); + errors.push("cannot write a buffer without a filename"); } return None; } diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index 61fca609..52dd49f9 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -145,6 +145,7 @@ where helix_view::editor::StatusLineElement::FileModificationIndicator => { render_file_modification_indicator } + helix_view::editor::StatusLineElement::ReadOnlyIndicator => render_read_only_indicator, helix_view::editor::StatusLineElement::FileEncoding => render_file_encoding, helix_view::editor::StatusLineElement::FileLineEnding => render_file_line_ending, helix_view::editor::StatusLineElement::FileType => render_file_type, @@ -442,6 +443,19 @@ where write(context, title, None); } +fn render_read_only_indicator<F>(context: &mut RenderContext, write: F) +where + F: Fn(&mut RenderContext, String, Option<Style>) + Copy, +{ + let title = if context.doc.readonly { + " [readonly] " + } else { + "" + } + .to_string(); + write(context, title, None); +} + fn render_file_base_name<F>(context: &mut RenderContext, write: F) where F: Fn(&mut RenderContext, String, Option<Style>) + Copy, diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 203b5dad..b66739a4 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -51,6 +51,7 @@ clipboard-win = { version = "4.5", features = ["std"] } [target.'cfg(unix)'.dependencies] libc = "0.2" +rustix = { version = "0.38", features = ["fs"] } [dev-dependencies] helix-tui = { path = "../helix-tui" } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index af7e3a7e..7602c9c7 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -185,6 +185,8 @@ pub struct Document { // when document was used for most-recent-used buffer picker pub focused_at: std::time::Instant, + + pub readonly: bool, } /// Inlay hints for a single `(Document, View)` combo. @@ -673,6 +675,7 @@ impl Document { config, version_control_head: None, focused_at: std::time::Instant::now(), + readonly: false, } } @@ -955,6 +958,33 @@ impl Document { } } + #[cfg(unix)] + // Detect if the file is readonly and change the readonly field if necessary (unix only) + pub fn detect_readonly(&mut self) { + use rustix::fs::{access, Access}; + // Allows setting the flag for files the user cannot modify, like root files + self.readonly = match &self.path { + None => false, + Some(p) => access(p, Access::WRITE_OK).is_err(), + }; + } + + #[cfg(not(unix))] + // Detect if the file is readonly and change the readonly field if necessary (non-unix os) + pub fn detect_readonly(&mut self) { + // TODO Use the Windows' function `CreateFileW` to check if a file is readonly + // Discussion: https://github.com/helix-editor/helix/pull/7740#issuecomment-1656806459 + // Vim implementation: https://github.com/vim/vim/blob/4c0089d696b8d1d5dc40568f25ea5738fa5bbffb/src/os_win32.c#L7665 + // Windows binding: https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Storage/FileSystem/fn.CreateFileW.html + self.readonly = match &self.path { + None => false, + Some(p) => match std::fs::metadata(p) { + Err(_) => false, + Ok(metadata) => metadata.permissions().readonly(), + }, + }; + } + /// Reload the document from its path. pub fn reload( &mut self, @@ -969,6 +999,9 @@ impl Document { .ok_or_else(|| anyhow!("can't find file to reload from {:?}", self.display_name()))? .to_owned(); + // Once we have a valid path we check if its readonly status has changed + self.detect_readonly(); + let mut file = std::fs::File::open(&path)?; let (rope, ..) = from_reader(&mut file, Some(encoding))?; @@ -1018,6 +1051,8 @@ impl Document { // and error out when document is saved self.path = path; + self.detect_readonly(); + Ok(()) } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 2152ff9b..113102b6 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -421,6 +421,7 @@ impl Default for StatusLineConfig { E::Mode, E::Spinner, E::FileName, + E::ReadOnlyIndicator, E::FileModificationIndicator, ], center: vec![], @@ -473,6 +474,9 @@ pub enum StatusLineElement { // The file modification indicator FileModificationIndicator, + /// An indicator that shows `"[readonly]"` when a file cannot be written + ReadOnlyIndicator, + /// The file encoding FileEncoding, |