Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement change_directory/show_directory commands #335

Merged
merged 2 commits into from
Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,41 @@ mod cmd {
editor.set_status(editor.clipboard_provider.name().into());
}

fn change_current_directory(editor: &mut Editor, args: &[&str], _: PromptEvent) {
let dir = match args.first() {
Some(dir) => dir,
None => {
editor.set_error("target directory not provided".into());
return;
}
};

if let Err(e) = std::env::set_current_dir(dir) {
editor.set_error(format!(
"Couldn't change the current working directory: {:?}",
e
));
return;
}

match std::env::current_dir() {
Ok(cwd) => editor.set_status(format!(
"Current working directory is now {}",
cwd.display()
)),
Err(e) => editor.set_error(format!("Couldn't get the new working directory: {}", e)),
}
}

fn show_current_directory(editor: &mut Editor, args: &[&str], _: PromptEvent) {
match std::env::current_dir() {
Ok(cwd) => editor.set_status(format!("Current working directory is {}", cwd.display())),
Err(e) => {
editor.set_error(format!("Couldn't get the current working directory: {}", e))
}
}
}

pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "quit",
Expand Down Expand Up @@ -1471,6 +1506,20 @@ mod cmd {
fun: show_clipboard_provider,
completer: None,
},
TypableCommand {
name: "change-current-directory",
alias: Some("cd"),
doc: "Change the current working directory (:cd <dir>).",
fun: change_current_directory,
completer: Some(completers::directory),
},
TypableCommand {
name: "show-directory",
alias: Some("pwd"),
doc: "Show the current working directory.",
fun: show_current_directory,
completer: None,
},
];

pub static COMMANDS: Lazy<HashMap<&'static str, &'static TypableCommand>> = Lazy::new(|| {
Expand Down
53 changes: 49 additions & 4 deletions helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,46 @@ pub mod completers {
names
}

// TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
pub fn filename(input: &str) -> Vec<Completion> {
filename_impl(input, |entry| {
let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());

if is_dir {
FileMatch::AcceptIncomplete
} else {
FileMatch::Accept
}
})
}

pub fn directory(input: &str) -> Vec<Completion> {
filename_impl(input, |entry| {
let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());

if is_dir {
FileMatch::Accept
} else {
FileMatch::Reject
}
})
}

#[derive(Copy, Clone, PartialEq, Eq)]
enum FileMatch {
/// Entry should be ignored
Reject,
/// Entry is usable but can't be the end (for instance if the entry is a directory and we
/// try to match a file)
AcceptIncomplete,
/// Entry is usable and can be the end of the match
Accept,
}

// TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
fn filename_impl<F>(input: &str, filter_fn: F) -> Vec<Completion>
where
F: Fn(&ignore::DirEntry) -> FileMatch,
{
// Rust's filename handling is really annoying.

use ignore::WalkBuilder;
Expand Down Expand Up @@ -186,7 +224,13 @@ pub mod completers {
.max_depth(Some(1))
.build()
.filter_map(|file| {
file.ok().map(|entry| {
file.ok().and_then(|entry| {
let fmatch = filter_fn(&entry);

if fmatch == FileMatch::Reject {
return None;
}

let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());

let path = entry.path();
Expand All @@ -201,11 +245,12 @@ pub mod completers {
path.strip_prefix(&dir).unwrap_or(path).to_path_buf()
};

if is_dir {
if fmatch == FileMatch::AcceptIncomplete {
path.push("");
}

let path = path.to_str().unwrap().to_owned();
(end.clone(), Cow::from(path))
Some((end.clone(), Cow::from(path)))
})
}) // TODO: unwrap or skip
.filter(|(_, path)| !path.is_empty()) // TODO
Expand Down