Open files with drag and drop, escape filenames

This commit is contained in:
Christopher Lübbemeier
2018-03-19 19:00:40 +01:00
parent fdaff9748a
commit 0c398c893a
6 changed files with 84 additions and 1 deletions

View File

@@ -15,6 +15,7 @@ use gtk::prelude::*;
use neovim_lib::{NeovimApi, NeovimApiAsync};
use misc::escape_filename;
use nvim::{ErrorReport, NeovimClient, NeovimRef};
use shell;
@@ -267,6 +268,7 @@ impl FileBrowserWidget {
} else {
&file_path
};
let file_path = escape_filename(file_path);
nvim_ref.nvim().unwrap().command_async(&format!(":e {}", file_path))
.cb(|r| r.report_err())
.call();

View File

@@ -11,13 +11,17 @@ extern crate gtk;
extern crate gtk_sys;
extern crate htmlescape;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate neovim_lib;
extern crate pango;
extern crate pango_cairo_sys;
extern crate pango_sys;
extern crate pangocairo;
extern crate percent_encoding;
extern crate phf;
extern crate regex;
extern crate serde;
#[macro_use]
@@ -50,6 +54,7 @@ mod tabline;
mod error;
mod file_browser;
mod subscriptions;
mod misc;
use std::env;
use std::time::Duration;
@@ -58,6 +63,7 @@ use gio::prelude::*;
use ui::Ui;
use misc::escape_filename;
use shell::ShellOptions;
const BIN_PATH_ARG: &str = "--nvim-bin-path";
@@ -101,7 +107,9 @@ fn open(app: &gtk::Application, files: &[gio::File], _: &str) {
for f in files {
let mut ui = Ui::new(ShellOptions::new(
nvim_bin_path(std::env::args()),
f.get_path().and_then(|p| p.to_str().map(str::to_owned)),
f.get_path().and_then(|p| {
p.to_str().map(|path| escape_filename(path).to_string())
}),
nvim_timeout(std::env::args()),
));

38
src/misc.rs Normal file
View File

@@ -0,0 +1,38 @@
use std::borrow::Cow;
use regex::Regex;
use percent_encoding::percent_decode;
/// Escape special ASCII characters with a backslash.
pub fn escape_filename<'t>(filename: &'t str) -> Cow<'t, str> {
lazy_static! {
static ref SPECIAL_CHARS: Regex = if cfg!(target_os = "windows") {
// On Windows, don't escape `:` and `\`, as these are valid components of the path.
Regex::new(r"[[:ascii:]&&[^0-9a-zA-Z._:\\-]]").unwrap()
} else {
// Similarly, don't escape `/` on other platforms.
Regex::new(r"[[:ascii:]&&[^0-9a-zA-Z._/-]]").unwrap()
};
}
SPECIAL_CHARS.replace_all(&*filename, r"\$0")
}
/// Decode a file URI.
///
/// - On UNIX: `file:///path/to/a%20file.ext` -> `/path/to/a file.ext`
/// - On Windows: `file:///C:/path/to/a%20file.ext` -> `C:\path\to\a file.ext`
pub fn decode_uri(uri: &str) -> Option<String> {
let path = match uri.split_at(8) {
("file:///", path) => path,
_ => return None,
};
let path = percent_decode(path.as_bytes()).decode_utf8().ok()?;
if cfg!(target_os = "windows") {
lazy_static! {
static ref SLASH: Regex = Regex::new(r"/").unwrap();
}
Some(String::from(SLASH.replace_all(&*path, r"\")))
} else {
Some("/".to_owned() + &path)
}
}

View File

@@ -18,6 +18,7 @@ use pangocairo;
use neovim_lib::{Neovim, NeovimApi, NeovimApiAsync, Value};
use neovim_lib::neovim_api::Tabpage;
use misc::{decode_uri, escape_filename};
use settings::{FontSource, Settings};
use ui_model::{Attrs, ModelRect, UiModel};
use color::{Color, ColorModel, COLOR_BLACK, COLOR_RED, COLOR_WHITE};
@@ -567,6 +568,28 @@ impl Shell {
state.drawing_area.connect_size_allocate(move |_, _| {
init_nvim(&ref_state);
});
let ref_state = self.state.clone();
let targets = vec![
gtk::TargetEntry::new("text/uri-list", gtk::TargetFlags::OTHER_APP, 0),
];
state
.drawing_area
.drag_dest_set(gtk::DestDefaults::ALL, &targets, gdk::DragAction::COPY);
state
.drawing_area
.connect_drag_data_received(move |_, _, _, _, s, _, _| {
let uris = s.get_uris();
let command = uris.iter()
.filter_map(|uri| decode_uri(uri))
.fold(":ar".to_owned(), |command, filename| {
let filename = escape_filename(&filename);
command + " " + &filename
});
let state = ref_state.borrow_mut();
let mut nvim = state.nvim().unwrap();
nvim.command_async(&command).cb(|r| r.report_err()).call()
});
}
#[cfg(unix)]