Add timeout option, set default timeout to 10sec(#24)

format
This commit is contained in:
daa 2017-12-10 12:46:36 +03:00
parent 68b610cef0
commit 7f061efa19
17 changed files with 296 additions and 191 deletions

View File

@ -30,4 +30,3 @@ fn get_xdg_config_dir() -> Result<PathBuf, String> {
home_dir.push(".config");
Ok(home_dir)
}

View File

@ -20,8 +20,8 @@ impl ErrorArea {
let label = gtk::Label::new(None);
label.set_line_wrap(true);
let error_image = gtk::Image::new_from_icon_name("dialog-error",
gtk_sys::GTK_ICON_SIZE_DIALOG as i32);
let error_image =
gtk::Image::new_from_icon_name("dialog-error", gtk_sys::GTK_ICON_SIZE_DIALOG as i32);
base.pack_start(&error_image, false, true, 10);
base.pack_start(&label, true, true, 1);

View File

@ -50,13 +50,16 @@ mod error;
use std::env;
use std::time::Duration;
use std::str::FromStr;
use gio::{ApplicationExt, FileExt};
use ui::Ui;
use shell::ShellOptions;
const BIN_PATH_ARG: &'static str = "--nvim-bin-path";
const BIN_PATH_ARG: &str = "--nvim-bin-path";
const TIMEOUT_ARG: &str = "--timeout";
fn main() {
env_logger::init().expect("Can't initialize env_logger");
@ -64,12 +67,10 @@ fn main() {
let app_flags = gio::APPLICATION_HANDLES_OPEN;
let app = if cfg!(debug_assertions) {
gtk::Application::new(Some("org.daa.NeovimGtkDebug"),
app_flags)
gtk::Application::new(Some("org.daa.NeovimGtkDebug"), app_flags)
} else {
gtk::Application::new(Some("org.daa.NeovimGtk"), app_flags)
}
.expect("Failed to initialize GTK application");
}.expect("Failed to initialize GTK application");
app.connect_activate(activate);
{
@ -82,6 +83,7 @@ fn main() {
let args: Vec<String> = env::args().collect();
let argv: Vec<&str> = args.iter()
.filter(|a| !a.starts_with(BIN_PATH_ARG))
.filter(|a| !a.starts_with(TIMEOUT_ARG))
.map(String::as_str)
.collect();
app.run(&argv);
@ -89,26 +91,49 @@ fn main() {
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))));
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)),
nvim_timeout(std::env::args()),
));
ui.init(app);
}
}
fn activate(app: &gtk::Application) {
let mut ui = Ui::new(ShellOptions::new(nvim_bin_path(std::env::args()), None));
let mut ui = Ui::new(ShellOptions::new(
nvim_bin_path(std::env::args()),
None,
nvim_timeout(std::env::args()),
));
ui.init(app);
}
fn nvim_bin_path<I>(args: I) -> Option<String>
where I: Iterator<Item = String>
fn nvim_bin_path<I>(mut args: I) -> Option<String>
where
I: Iterator<Item = String>,
{
args.skip_while(|a| !a.starts_with(BIN_PATH_ARG))
.map(|p| p.split('=').nth(1).map(str::to_owned))
.nth(0)
.unwrap_or(None)
args.find(|a| a.starts_with(BIN_PATH_ARG)).and_then(|p| {
p.split('=').nth(1).map(str::to_owned)
})
}
fn nvim_timeout<I>(mut args: I) -> Option<Duration>
where
I: Iterator<Item = String>,
{
args.find(|a| a.starts_with(TIMEOUT_ARG))
.and_then(|p| p.split('=').nth(1).map(str::to_owned))
.and_then(|timeout| match u64::from_str(&timeout) {
Ok(timeout) => Some(timeout),
Err(err) => {
error!("Can't convert timeout argument to integer: {}", err);
None
}
})
.map(|timeout| Duration::from_secs(timeout))
}
#[cfg(test)]
@ -117,9 +142,24 @@ mod tests {
#[test]
fn test_bin_path_arg() {
assert_eq!(Some("/test_path".to_string()),
nvim_bin_path(vec!["neovim-gtk", "--nvim-bin-path=/test_path"]
assert_eq!(
Some("/test_path".to_string()),
nvim_bin_path(
vec!["neovim-gtk", "--nvim-bin-path=/test_path"]
.iter()
.map(|s| s.to_string())));
.map(|s| s.to_string()),
)
);
}
#[test]
fn test_timeout_arg() {
assert_eq!(
Some(Duration::from_secs(100)),
nvim_timeout(vec!["neovim-gtk", "--timeout=100"].iter().map(
|s| s.to_string(),
))
);
}
}

View File

@ -27,9 +27,7 @@ impl Mode {
}
pub fn mode_info(&self) -> Option<&nvim::ModeInfo> {
self.info
.as_ref()
.and_then(|i| i.get(self.idx))
self.info.as_ref().and_then(|i| i.get(self.idx))
}
pub fn update(&mut self, mode: &str, idx: usize) {

View File

@ -16,6 +16,7 @@ use std::env;
use std::process::{Stdio, Command};
use std::result;
use std::sync::Arc;
use std::time::Duration;
use neovim_lib::{Neovim, NeovimApi, Session, UiAttachOptions, CallError};
@ -78,6 +79,7 @@ impl error::Error for NvimInitError {
pub fn start(
shell: Arc<UiMutex<shell::State>>,
nvim_bin_path: Option<&String>,
timeout: Option<Duration>,
) -> result::Result<Neovim, NvimInitError> {
let mut cmd = if let Some(path) = nvim_bin_path {
Command::new(path)
@ -116,11 +118,13 @@ pub fn start(
let session = Session::new_child_cmd(&mut cmd);
let session = match session {
let mut session = match session {
Err(e) => return Err(NvimInitError::new(&cmd, e)),
Ok(s) => s,
};
session.set_timeout(timeout.unwrap_or(Duration::from_millis(10_000)));
let mut nvim = Neovim::new(session);
nvim.session.start_event_loop_handler(
@ -139,17 +143,20 @@ pub fn post_start_init(
let mut opts = UiAttachOptions::new();
opts.set_popupmenu_external(true);
opts.set_tabline_external(true);
nvim.borrow().unwrap().ui_attach(cols, rows, &opts).map_err(
NvimInitError::new_post_init,
)?;
nvim.borrow().unwrap().command("runtime! ginit.vim").map_err(
NvimInitError::new_post_init,
)?;
nvim.borrow()
.unwrap()
.ui_attach(cols, rows, &opts)
.map_err(NvimInitError::new_post_init)?;
nvim.borrow()
.unwrap()
.command("runtime! ginit.vim")
.map_err(NvimInitError::new_post_init)?;
if let Some(path) = open_path {
nvim.borrow().unwrap().command(&format!("e {}", path)).map_err(
NvimInitError::new_post_init,
)?;
nvim.borrow()
.unwrap()
.command(&format!("e {}", path))
.map_err(NvimInitError::new_post_init)?;
}
Ok(())
@ -175,4 +182,3 @@ impl<T> ErrorReport<T> for result::Result<T, CallError> {
self.ok()
}
}

View File

@ -229,4 +229,3 @@ pub fn call(
Ok(repaint_mode)
}

View File

@ -106,7 +106,11 @@ impl PlugManagerConfigSource {
for plug in store.get_plugs() {
if !plug.removed {
builder += &format!("Plug '{}', {{ 'as': '{}' }}\n", plug.get_plug_path(), plug.name);
builder += &format!(
"Plug '{}', {{ 'as': '{}' }}\n",
plug.get_plug_path(),
plug.name
);
}
}

View File

@ -68,7 +68,10 @@ impl Store {
pub fn add_plug(&mut self, plug: PlugInfo) -> bool {
let path = plug.get_plug_path();
if self.settings.plugs.iter().any(|p| p.get_plug_path() == path || p.name == plug.name) {
if self.settings.plugs.iter().any(|p| {
p.get_plug_path() == path || p.name == plug.name
})
{
return false;
}
self.settings.plugs.push(plug);
@ -81,7 +84,10 @@ impl Store {
pub fn move_item(&mut self, idx: usize, offset: i32) {
let plug = self.settings.plugs.remove(idx);
self.settings.plugs.insert((idx as i32 + offset) as usize, plug);
self.settings.plugs.insert(
(idx as i32 + offset) as usize,
plug,
);
}
}
@ -93,7 +99,10 @@ struct Settings {
impl Settings {
fn new(plugs: Vec<PlugInfo>) -> Self {
Settings { plugs, enabled: false }
Settings {
plugs,
enabled: false,
}
}
}
@ -101,7 +110,10 @@ impl SettingsLoader for Settings {
const SETTINGS_FILE: &'static str = "plugs.toml";
fn empty() -> Self {
Settings { plugs: vec![], enabled: false }
Settings {
plugs: vec![],
enabled: false,
}
}
fn from_str(s: &str) -> Result<Self, String> {

View File

@ -43,7 +43,9 @@ impl<'a> Ui<'a> {
let header_bar = gtk::HeaderBar::new();
let add_plug_btn = gtk::Button::new_with_label("Add..");
add_plug_btn.get_style_context().map(|c| c.add_class("suggested-action"));
add_plug_btn.get_style_context().map(|c| {
c.add_class("suggested-action")
});
header_bar.pack_end(&add_plug_btn);
@ -116,7 +118,9 @@ impl<'a> Ui<'a> {
let mut manager = self.manager.borrow_mut();
manager.clear_removed();
manager.save();
if let Some(config_path) = NvimConfig::new(manager.generate_config()).generate_config() {
if let Some(config_path) =
NvimConfig::new(manager.generate_config()).generate_config()
{
if let Some(path) = config_path.to_str() {
manager.vim_plug.reload(path);
}
@ -156,8 +160,10 @@ fn create_up_down_btns(
manager: &Arc<UiMutex<manager::Manager>>,
) -> gtk::Box {
let buttons_panel = gtk::Box::new(gtk::Orientation::Horizontal, 5);
let up_btn = gtk::Button::new_from_icon_name("go-up-symbolic", gtk_sys::GTK_ICON_SIZE_BUTTON as i32);
let down_btn = gtk::Button::new_from_icon_name("go-down-symbolic", gtk_sys::GTK_ICON_SIZE_BUTTON as i32);
let up_btn =
gtk::Button::new_from_icon_name("go-up-symbolic", gtk_sys::GTK_ICON_SIZE_BUTTON as i32);
let down_btn =
gtk::Button::new_from_icon_name("go-down-symbolic", gtk_sys::GTK_ICON_SIZE_BUTTON as i32);
up_btn.connect_clicked(clone!(plugs_panel, manager => move |_| {
if let Some(row) = plugs_panel.get_selected_row() {

View File

@ -84,7 +84,9 @@ impl Manager {
pub fn reload(&self, path: &str) {
if let Some(mut nvim) = self.nvim() {
nvim.command(&format!("source {}", path)).report_err(&mut *nvim);
nvim.command(&format!("source {}", path)).report_err(
&mut *nvim,
);
}
}
}
@ -100,4 +102,3 @@ impl VimPlugInfo {
VimPlugInfo { name, uri }
}
}

View File

@ -42,7 +42,8 @@ fn request(query: Option<&str>) -> io::Result<DescriptionList> {
if out.stdout.is_empty() {
Ok(DescriptionList::empty())
} else {
let description_list: DescriptionList = serde_json::from_slice(&out.stdout).map_err(|e| {
let description_list: DescriptionList =
serde_json::from_slice(&out.stdout).map_err(|e| {
io::Error::new(io::ErrorKind::Other, e)
})?;
Ok(description_list)
@ -147,9 +148,7 @@ pub struct DescriptionList {
impl DescriptionList {
fn empty() -> DescriptionList {
DescriptionList {
plugins: Box::new([]),
}
DescriptionList { plugins: Box::new([]) }
}
}

View File

@ -30,18 +30,22 @@ enum ProjectViewColumns {
}
const COLUMN_COUNT: usize = 6;
const COLUMN_TYPES: [Type; COLUMN_COUNT] = [Type::String,
const COLUMN_TYPES: [Type; COLUMN_COUNT] = [
Type::String,
Type::String,
Type::String,
Type::String,
Type::Bool,
Type::Bool];
const COLUMN_IDS: [u32; COLUMN_COUNT] = [ProjectViewColumns::Name as u32,
Type::Bool,
];
const COLUMN_IDS: [u32; COLUMN_COUNT] = [
ProjectViewColumns::Name as u32,
ProjectViewColumns::Path as u32,
ProjectViewColumns::Uri as u32,
ProjectViewColumns::Pixbuf as u32,
ProjectViewColumns::Project as u32,
ProjectViewColumns::ProjectStored as u32];
ProjectViewColumns::ProjectStored as u32,
];
pub struct Projects {
shell: Rc<RefCell<Shell>>,
@ -79,9 +83,10 @@ impl Projects {
vbox.pack_start(&search_box, false, true, 0);
projects
.scroll
.set_policy(PolicyType::Never, PolicyType::Automatic);
projects.scroll.set_policy(
PolicyType::Never,
PolicyType::Automatic,
);
projects.scroll.add(&projects.tree);
@ -97,10 +102,9 @@ impl Projects {
let projects = Rc::new(RefCell::new(projects));
let prj_ref = projects.clone();
projects
.borrow()
.tree
.connect_size_allocate(move |_, _| on_treeview_allocate(prj_ref.clone()));
projects.borrow().tree.connect_size_allocate(move |_, _| {
on_treeview_allocate(prj_ref.clone())
});
let prj_ref = projects.clone();
search_box.connect_changed(move |search_box| {
@ -124,17 +128,16 @@ impl Projects {
});
let prj_ref = projects.clone();
projects
.borrow()
.tree
.connect_row_activated(move |tree, _, _| {
projects.borrow().tree.connect_row_activated(
move |tree, _, _| {
let selection = tree.get_selection();
if let Some((model, iter)) = selection.get_selected() {
prj_ref.borrow().open_uri(&model, &iter);
let popup = prj_ref.borrow().popup.clone();
popup.popdown();
}
});
},
);
let prj_ref = projects.clone();
open_btn.connect_clicked(move |_| {
@ -144,16 +147,16 @@ impl Projects {
});
let prj_ref = projects.clone();
projects
.borrow()
.popup
.connect_closed(move |_| prj_ref.borrow_mut().clear());
projects.borrow().popup.connect_closed(
move |_| prj_ref.borrow_mut().clear(),
);
let prj_ref = projects.clone();
projects
.borrow()
.toggle_renderer
.connect_toggled(move |_, path| prj_ref.borrow_mut().toggle_stored(&path));
projects.borrow().toggle_renderer.connect_toggled(
move |_, path| {
prj_ref.borrow_mut().toggle_stored(&path)
},
);
projects
}
@ -165,9 +168,11 @@ impl Projects {
.get()
.unwrap();
list_store.set_value(&iter,
list_store.set_value(
&iter,
ProjectViewColumns::ProjectStored as u32,
&ToValue::to_value(&!value));
&ToValue::to_value(&!value),
);
let pixbuf = if value {
CURRENT_DIR_PIXBUF
@ -175,9 +180,11 @@ impl Projects {
BOOKMARKED_PIXBUF
};
list_store.set_value(&iter,
list_store.set_value(
&iter,
ProjectViewColumns::Pixbuf as u32,
&ToValue::to_value(pixbuf));
&ToValue::to_value(pixbuf),
);
let uri_value = list_store.get_value(&iter, ProjectViewColumns::Uri as i32);
let uri: String = uri_value.get().unwrap();
@ -194,8 +201,14 @@ impl Projects {
fn open_uri(&self, model: &TreeModel, iter: &TreeIter) {
let uri: String = model.get_value(iter, ProjectViewColumns::Uri as i32).get().unwrap();
let project: bool = model.get_value(iter, ProjectViewColumns::Project as i32).get().unwrap();
let uri: String = model
.get_value(iter, ProjectViewColumns::Uri as i32)
.get()
.unwrap();
let project: bool = model
.get_value(iter, ProjectViewColumns::Project as i32)
.get()
.unwrap();
let shell = self.shell.borrow();
if project {
@ -218,9 +231,11 @@ impl Projects {
.unwrap()
.downcast::<gtk::Window>()
.ok();
let dlg = gtk::FileChooserDialog::new(Some("Open Document"),
let dlg = gtk::FileChooserDialog::new(
Some("Open Document"),
window.as_ref(),
gtk::FileChooserAction::Open);
gtk::FileChooserAction::Open,
);
const OPEN_ID: i32 = 0;
const CANCEL_ID: i32 = 1;
@ -268,9 +283,11 @@ impl Projects {
let icon_renderer = CellRendererPixbuf::new();
image_column.pack_start(&icon_renderer, true);
image_column.add_attribute(&icon_renderer,
image_column.add_attribute(
&icon_renderer,
"icon-name",
ProjectViewColumns::Pixbuf as i32);
ProjectViewColumns::Pixbuf as i32,
);
self.tree.append_column(&image_column);
@ -278,18 +295,23 @@ impl Projects {
self.name_renderer.set_property_width_chars(60);
self.path_renderer.set_property_width_chars(60);
self.path_renderer
.set_property_ellipsize(pango::EllipsizeMode::Start);
self.path_renderer.set_property_ellipsize(
pango::EllipsizeMode::Start,
);
text_column.pack_start(&self.name_renderer, true);
text_column.pack_start(&self.path_renderer, true);
text_column.add_attribute(&self.name_renderer,
text_column.add_attribute(
&self.name_renderer,
"markup",
ProjectViewColumns::Name as i32);
text_column.add_attribute(&self.path_renderer,
ProjectViewColumns::Name as i32,
);
text_column.add_attribute(
&self.path_renderer,
"markup",
ProjectViewColumns::Path as i32);
ProjectViewColumns::Path as i32,
);
let area = text_column
.get_area()
@ -306,12 +328,16 @@ impl Projects {
self.toggle_renderer.set_padding(10, 0);
toggle_column.pack_start(&self.toggle_renderer, true);
toggle_column.add_attribute(&self.toggle_renderer,
toggle_column.add_attribute(
&self.toggle_renderer,
"visible",
ProjectViewColumns::Project as i32);
toggle_column.add_attribute(&self.toggle_renderer,
ProjectViewColumns::Project as i32,
);
toggle_column.add_attribute(
&self.toggle_renderer,
"active",
ProjectViewColumns::ProjectStored as i32);
ProjectViewColumns::ProjectStored as i32,
);
self.tree.append_column(&toggle_column);
}
@ -381,9 +407,7 @@ pub struct EntryStore {
impl EntryStore {
pub fn find_mut(&mut self, uri: &str) -> Option<&mut Entry> {
self.entries
.iter_mut()
.find(|e| e.project && e.uri == uri)
self.entries.iter_mut().find(|e| e.project && e.uri == uri)
}
pub fn load(nvim: &mut Neovim) -> EntryStore {
@ -396,10 +420,7 @@ impl EntryStore {
match nvim.call_function("getcwd", vec![]) {
Ok(pwd) => {
if let Some(pwd) = pwd.as_str() {
if entries
.iter()
.find(|e| e.project && e.uri == pwd)
.is_none() {
if entries.iter().find(|e| e.project && e.uri == pwd).is_none() {
entries.insert(0, Entry::new_current_project(pwd));
}
} else {
@ -420,12 +441,13 @@ impl EntryStore {
pub fn save(&self) {
if self.changed {
ProjectSettings::new(self.entries
ProjectSettings::new(
self.entries
.iter()
.filter(|e| e.project && e.stored)
.map(|p| p.to_entry_settings())
.collect())
.save();
.collect(),
).save();
}
}
@ -437,7 +459,8 @@ impl EntryStore {
file.path.to_uppercase().contains(filter)
}
None => true,
} {
}
{
list_store.insert_with_values(None, &COLUMN_IDS, &file.to_values());
}
}
@ -465,7 +488,9 @@ impl Entry {
Entry {
uri: uri.to_owned(),
path: path.parent()
.map(|s| format!("<small>{}</small>", encode_minimal(&s.to_string_lossy())))
.map(|s| {
format!("<small>{}</small>", encode_minimal(&s.to_string_lossy()))
})
.unwrap_or_else(|| "".to_owned()),
file_name: format!("<big>{}</big>", encode_minimal(name)),
name: name.to_owned(),
@ -484,7 +509,9 @@ impl Entry {
Entry {
uri: uri.to_owned(),
path: path.parent()
.map(|s| format!("<small>{}</small>", encode_minimal(&s.to_string_lossy())))
.map(|s| {
format!("<small>{}</small>", encode_minimal(&s.to_string_lossy()))
})
.unwrap_or_else(|| "".to_owned()),
file_name: format!("<big>{}</big>", encode_minimal(&name)),
name,
@ -504,8 +531,7 @@ impl Entry {
uri: uri.to_owned(),
path: path.parent()
.map(|s| {
format!("<small>{}</small>",
encode_minimal(&s.to_string_lossy()))
format!("<small>{}</small>", encode_minimal(&s.to_string_lossy()))
})
.unwrap_or_else(|| "".to_owned()),
file_name: format!("<big>{}</big>", encode_minimal(&name)),
@ -517,12 +543,16 @@ impl Entry {
}
fn to_values(&self) -> Box<[&gtk::ToValue]> {
Box::new([&self.file_name,
Box::new(
[
&self.file_name,
&self.path,
&self.uri,
&self.pixbuf,
&self.project,
&self.stored])
&self.stored,
],
)
}
fn to_entry_settings(&self) -> ProjectEntrySettings {
@ -576,4 +606,3 @@ impl ProjectSettings {
ProjectSettings { projects }
}
}

View File

@ -3,6 +3,7 @@ use std::rc::Rc;
use std::sync::{Arc, Condvar, Mutex};
use std::ops::Deref;
use std::thread;
use std::time::Duration;
use cairo;
use pangocairo::CairoContextExt;
@ -358,13 +359,19 @@ impl UiState {
pub struct ShellOptions {
nvim_bin_path: Option<String>,
open_path: Option<String>,
timeout: Option<Duration>,
}
impl ShellOptions {
pub fn new(nvim_bin_path: Option<String>, open_path: Option<String>) -> Self {
pub fn new(
nvim_bin_path: Option<String>,
open_path: Option<String>,
timeout: Option<Duration>,
) -> Self {
ShellOptions {
nvim_bin_path,
open_path,
timeout,
}
}
}
@ -763,7 +770,11 @@ fn init_nvim_async(
rows: usize,
) {
// execute nvim
let nvim = match nvim::start(state_arc.clone(), options.nvim_bin_path.as_ref()) {
let nvim = match nvim::start(
state_arc.clone(),
options.nvim_bin_path.as_ref(),
options.timeout,
) {
Ok(nvim) => nvim,
Err(err) => {
show_nvim_start_error(&err, state_arc);

View File

@ -5,15 +5,13 @@ use glib::translate::*;
pub struct Analysis<'a>(&'a pango_sys::PangoAnalysis);
impl <'a> Analysis <'a> {
impl<'a> Analysis<'a> {
pub fn from(analysis: &'a pango_sys::PangoAnalysis) -> Self {
Analysis(analysis)
}
pub fn font(&self) -> pango::Font {
unsafe {
from_glib_none(self.0.font)
}
unsafe { from_glib_none(self.0.font) }
}
pub fn to_glib_ptr(&self) -> *const pango_sys::PangoAnalysis {

View File

@ -22,9 +22,7 @@ glib_wrapper! {
impl Item {
#[cfg(test)]
pub fn new() -> Self {
unsafe {
from_glib_full(pango_sys::pango_item_new())
}
unsafe { from_glib_full(pango_sys::pango_item_new()) }
}
pub fn analysis(&self) -> analysis::Analysis {
@ -32,6 +30,10 @@ impl Item {
}
pub fn offset(&self) -> (usize, usize, usize) {
(self.0.offset as usize, self.0.length as usize, self.0.num_chars as usize)
(
self.0.offset as usize,
self.0.length as usize,
self.0.num_chars as usize,
)
}
}

View File

@ -30,7 +30,9 @@ pub fn pango_itemize(
start_index as i32,
length as i32,
attrs.to_glib_none().0,
cached_iter.map(|iter| iter.to_glib_none_mut().0).unwrap_or(ptr::null_mut()),
cached_iter
.map(|iter| iter.to_glib_none_mut().0)
.unwrap_or(ptr::null_mut()),
))
}
}
@ -59,4 +61,3 @@ pub fn pango_shape(
);
}
}