Skip to content

Commit

Permalink
Show whether file readonly in statusline (helix-editor#7740)
Browse files Browse the repository at this point in the history
  • Loading branch information
connortsui20 authored and mtoohey31 committed Jun 2, 2024
1 parent 814fec3 commit 6654d89
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion book/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 | `"│"` |
Expand All @@ -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 |
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
14 changes: 14 additions & 0 deletions helix-term/src/ui/statusline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions helix-view/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
35 changes: 35 additions & 0 deletions helix-view/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -673,6 +675,7 @@ impl Document {
config,
version_control_head: None,
focused_at: std::time::Instant::now(),
readonly: false,
}
}

Expand Down Expand Up @@ -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,
Expand All @@ -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))?;

Expand Down Expand Up @@ -1018,6 +1051,8 @@ impl Document {
// and error out when document is saved
self.path = path;

self.detect_readonly();

Ok(())
}

Expand Down
4 changes: 4 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ impl Default for StatusLineConfig {
E::Mode,
E::Spinner,
E::FileName,
E::ReadOnlyIndicator,
E::FileModificationIndicator,
],
center: vec![],
Expand Down Expand Up @@ -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,

Expand Down

0 comments on commit 6654d89

Please sign in to comment.