on master help sign in
Allow setting a filepath on :write
commitce25aa951e4bd4352fc211258014557e69cc5c5c authorBlaž Hrastnik <blaz@mxxn.io> dateTue 1 Jun 2021, 14:47 (5 years ago) parenta2147fc
2 files changed+58−2
helix-term/src/commands.rs+7−1 helix-view/src/document.rs+51−1
helix-term/src/commands.rs+7−1
@@ -898,6 +898,12 @@ mod cmd {
898898
899899 fn write(editor: &mut Editor, args: &[&str], event: PromptEvent) {
900900 let (view, doc) = editor.current();
901+ if let Some(path) = args.get(0) {
902+ if let Err(err) = doc.set_path(Path::new(path)) {
903+ editor.set_error(format!("invalid filepath: {}", err));
904+ return;
905+ };
906+ }
901907 if doc.path().is_none() {
902908 editor.set_error("cannot write a buffer without a filename".to_string());
903909 return;
@@ -941,7 +947,7 @@ mod cmd {
941947 Command {
942948 name: "write",
943949 alias: Some("w"),
944− doc: "Write changes to disk.",
950+ doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)",
945951 fun: write,
946952 completer: Some(completers::filename),
947953 },
helix-view/src/document.rs+51−1
@@ -1,6 +1,6 @@
11use anyhow::{Context, Error};
22use std::future::Future;
3−use std::path::{Path, PathBuf};
3+use std::path::{Component, Path, PathBuf};
44use std::sync::Arc;
55
66use helix_core::{
@@ -64,6 +64,42 @@ where
6464 }
6565}
6666
67+/// Normalize a path, removing things like `.` and `..`.
68+///
69+/// CAUTION: This does not resolve symlinks (unlike
70+/// [`std::fs::canonicalize`]). This may cause incorrect or surprising
71+/// behavior at times. This should be used carefully. Unfortunately,
72+/// [`std::fs::canonicalize`] can be hard to use correctly, since it can often
73+/// fail, or on Windows returns annoying device paths. This is a problem Cargo
74+/// needs to improve on.
75+/// Copied from cargo: https://github.com/rust-lang/cargo/blob/070e459c2d8b79c5b2ac5218064e7603329c92ae/crates/cargo-util/src/paths.rs#L81
76+pub fn normalize_path(path: &Path) -> PathBuf {
77+ let mut components = path.components().peekable();
78+ let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
79+ components.next();
80+ PathBuf::from(c.as_os_str())
81+ } else {
82+ PathBuf::new()
83+ };
84+
85+ for component in components {
86+ match component {
87+ Component::Prefix(..) => unreachable!(),
88+ Component::RootDir => {
89+ ret.push(component.as_os_str());
90+ }
91+ Component::CurDir => {}
92+ Component::ParentDir => {
93+ ret.pop();
94+ }
95+ Component::Normal(c) => {
96+ ret.push(c);
97+ }
98+ }
99+ }
100+ ret
101+}
102+
67103use helix_lsp::lsp;
68104use url::Url;
69105
@@ -176,6 +212,20 @@ impl Document {
176212 }
177213 }
178214
215+ pub fn set_path(&mut self, path: &Path) -> Result<(), std::io::Error> {
216+ // canonicalize path to absolute value
217+ let current_dir = std::env::current_dir()?;
218+ let path = normalize_path(&current_dir.join(path));
219+
220+ if let Some(parent) = path.parent() {
221+ // TODO: return error as necessary
222+ if parent.exists() {
223+ self.path = Some(path);
224+ }
225+ }
226+ Ok(())
227+ }
228+
179229 pub fn set_language(
180230 &mut self,
181231 language_config: Option<Arc<helix_core::syntax::LanguageConfiguration>>,