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"); home_dir.push(".config");
Ok(home_dir) Ok(home_dir)
} }

View File

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

View File

@ -50,13 +50,16 @@ mod error;
use std::env; use std::env;
use std::time::Duration;
use std::str::FromStr;
use gio::{ApplicationExt, FileExt}; use gio::{ApplicationExt, FileExt};
use ui::Ui; use ui::Ui;
use shell::ShellOptions; 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() { fn main() {
env_logger::init().expect("Can't initialize env_logger"); env_logger::init().expect("Can't initialize env_logger");
@ -64,12 +67,10 @@ fn main() {
let app_flags = gio::APPLICATION_HANDLES_OPEN; let app_flags = gio::APPLICATION_HANDLES_OPEN;
let app = if cfg!(debug_assertions) { let app = if cfg!(debug_assertions) {
gtk::Application::new(Some("org.daa.NeovimGtkDebug"), gtk::Application::new(Some("org.daa.NeovimGtkDebug"), app_flags)
app_flags) } else {
} else { gtk::Application::new(Some("org.daa.NeovimGtk"), app_flags)
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); app.connect_activate(activate);
{ {
@ -82,6 +83,7 @@ fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let argv: Vec<&str> = args.iter() let argv: Vec<&str> = args.iter()
.filter(|a| !a.starts_with(BIN_PATH_ARG)) .filter(|a| !a.starts_with(BIN_PATH_ARG))
.filter(|a| !a.starts_with(TIMEOUT_ARG))
.map(String::as_str) .map(String::as_str)
.collect(); .collect();
app.run(&argv); app.run(&argv);
@ -89,26 +91,49 @@ fn main() {
fn open(app: &gtk::Application, files: &[gio::File], _: &str) { fn open(app: &gtk::Application, files: &[gio::File], _: &str) {
for f in files { for f in files {
let mut ui = Ui::new(ShellOptions::new(nvim_bin_path(std::env::args()), let mut ui = Ui::new(ShellOptions::new(
f.get_path().and_then(|p| p.to_str().map(str::to_owned)))); 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); ui.init(app);
} }
} }
fn activate(app: &gtk::Application) { 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); ui.init(app);
} }
fn nvim_bin_path<I>(args: I) -> Option<String> fn nvim_bin_path<I>(mut args: I) -> Option<String>
where I: Iterator<Item = String> where
I: Iterator<Item = String>,
{ {
args.skip_while(|a| !a.starts_with(BIN_PATH_ARG)) args.find(|a| a.starts_with(BIN_PATH_ARG)).and_then(|p| {
.map(|p| p.split('=').nth(1).map(str::to_owned)) p.split('=').nth(1).map(str::to_owned)
.nth(0) })
.unwrap_or(None) }
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)] #[cfg(test)]
@ -117,9 +142,24 @@ mod tests {
#[test] #[test]
fn test_bin_path_arg() { fn test_bin_path_arg() {
assert_eq!(Some("/test_path".to_string()), assert_eq!(
nvim_bin_path(vec!["neovim-gtk", "--nvim-bin-path=/test_path"] Some("/test_path".to_string()),
.iter() nvim_bin_path(
.map(|s| s.to_string()))); vec!["neovim-gtk", "--nvim-bin-path=/test_path"]
.iter()
.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> { pub fn mode_info(&self) -> Option<&nvim::ModeInfo> {
self.info self.info.as_ref().and_then(|i| i.get(self.idx))
.as_ref()
.and_then(|i| i.get(self.idx))
} }
pub fn update(&mut self, mode: &str, idx: usize) { 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::process::{Stdio, Command};
use std::result; use std::result;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use neovim_lib::{Neovim, NeovimApi, Session, UiAttachOptions, CallError}; use neovim_lib::{Neovim, NeovimApi, Session, UiAttachOptions, CallError};
@ -78,6 +79,7 @@ impl error::Error for NvimInitError {
pub fn start( pub fn start(
shell: Arc<UiMutex<shell::State>>, shell: Arc<UiMutex<shell::State>>,
nvim_bin_path: Option<&String>, nvim_bin_path: Option<&String>,
timeout: Option<Duration>,
) -> result::Result<Neovim, NvimInitError> { ) -> result::Result<Neovim, NvimInitError> {
let mut cmd = if let Some(path) = nvim_bin_path { let mut cmd = if let Some(path) = nvim_bin_path {
Command::new(path) Command::new(path)
@ -116,11 +118,13 @@ pub fn start(
let session = Session::new_child_cmd(&mut cmd); 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)), Err(e) => return Err(NvimInitError::new(&cmd, e)),
Ok(s) => s, Ok(s) => s,
}; };
session.set_timeout(timeout.unwrap_or(Duration::from_millis(10_000)));
let mut nvim = Neovim::new(session); let mut nvim = Neovim::new(session);
nvim.session.start_event_loop_handler( nvim.session.start_event_loop_handler(
@ -139,17 +143,20 @@ pub fn post_start_init(
let mut opts = UiAttachOptions::new(); let mut opts = UiAttachOptions::new();
opts.set_popupmenu_external(true); opts.set_popupmenu_external(true);
opts.set_tabline_external(true); opts.set_tabline_external(true);
nvim.borrow().unwrap().ui_attach(cols, rows, &opts).map_err( nvim.borrow()
NvimInitError::new_post_init, .unwrap()
)?; .ui_attach(cols, rows, &opts)
nvim.borrow().unwrap().command("runtime! ginit.vim").map_err( .map_err(NvimInitError::new_post_init)?;
NvimInitError::new_post_init, nvim.borrow()
)?; .unwrap()
.command("runtime! ginit.vim")
.map_err(NvimInitError::new_post_init)?;
if let Some(path) = open_path { if let Some(path) = open_path {
nvim.borrow().unwrap().command(&format!("e {}", path)).map_err( nvim.borrow()
NvimInitError::new_post_init, .unwrap()
)?; .command(&format!("e {}", path))
.map_err(NvimInitError::new_post_init)?;
} }
Ok(()) Ok(())
@ -159,7 +166,7 @@ pub fn post_start_init(
pub trait ErrorReport<T> { pub trait ErrorReport<T> {
fn report_err(&self, nvim: &mut NeovimApi); fn report_err(&self, nvim: &mut NeovimApi);
fn ok_and_report(self, nvim: &mut NeovimApi) -> Option<T>; fn ok_and_report(self, nvim: &mut NeovimApi) -> Option<T>;
} }
impl<T> ErrorReport<T> for result::Result<T, CallError> { impl<T> ErrorReport<T> for result::Result<T, CallError> {
@ -175,4 +182,3 @@ impl<T> ErrorReport<T> for result::Result<T, CallError> {
self.ok() self.ok()
} }
} }

View File

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

View File

@ -56,13 +56,13 @@ impl Manager {
} }
} }
PlugManageState::VimPlug => { PlugManageState::VimPlug => {
if Store::is_config_exists() { if Store::is_config_exists() {
self.store = Store::load(); self.store = Store::load();
self.plug_manage_state = PlugManageState::NvimGtk; self.plug_manage_state = PlugManageState::NvimGtk;
} else { } else {
self.store = Store::empty(); self.store = Store::empty();
} }
} }
} }
if let PlugManageState::Unknown = self.plug_manage_state { if let PlugManageState::Unknown = self.plug_manage_state {
if self.vim_plug.is_loaded() { if self.vim_plug.is_loaded() {
@ -106,7 +106,11 @@ impl PlugManagerConfigSource {
for plug in store.get_plugs() { for plug in store.get_plugs() {
if !plug.removed { 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 { pub fn add_plug(&mut self, plug: PlugInfo) -> bool {
let path = plug.get_plug_path(); 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; return false;
} }
self.settings.plugs.push(plug); self.settings.plugs.push(plug);
@ -81,7 +84,10 @@ impl Store {
pub fn move_item(&mut self, idx: usize, offset: i32) { pub fn move_item(&mut self, idx: usize, offset: i32) {
let plug = self.settings.plugs.remove(idx); 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 { impl Settings {
fn new(plugs: Vec<PlugInfo>) -> Self { 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"; const SETTINGS_FILE: &'static str = "plugs.toml";
fn empty() -> Self { fn empty() -> Self {
Settings { plugs: vec![], enabled: false } Settings {
plugs: vec![],
enabled: false,
}
} }
fn from_str(s: &str) -> Result<Self, String> { 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 header_bar = gtk::HeaderBar::new();
let add_plug_btn = gtk::Button::new_with_label("Add.."); 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); header_bar.pack_end(&add_plug_btn);
@ -116,7 +118,9 @@ impl<'a> Ui<'a> {
let mut manager = self.manager.borrow_mut(); let mut manager = self.manager.borrow_mut();
manager.clear_removed(); manager.clear_removed();
manager.save(); 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() { if let Some(path) = config_path.to_str() {
manager.vim_plug.reload(path); manager.vim_plug.reload(path);
} }
@ -156,8 +160,10 @@ fn create_up_down_btns(
manager: &Arc<UiMutex<manager::Manager>>, manager: &Arc<UiMutex<manager::Manager>>,
) -> gtk::Box { ) -> gtk::Box {
let buttons_panel = gtk::Box::new(gtk::Orientation::Horizontal, 5); 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 up_btn =
let down_btn = gtk::Button::new_from_icon_name("go-down-symbolic", gtk_sys::GTK_ICON_SIZE_BUTTON as i32); 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 |_| { up_btn.connect_clicked(clone!(plugs_panel, manager => move |_| {
if let Some(row) = plugs_panel.get_selected_row() { if let Some(row) = plugs_panel.get_selected_row() {

View File

@ -84,7 +84,9 @@ impl Manager {
pub fn reload(&self, path: &str) { pub fn reload(&self, path: &str) {
if let Some(mut nvim) = self.nvim() { 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 } VimPlugInfo { name, uri }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ impl ValueMapExt for Vec<(Value, Value)> {
.ok_or_else(|| "Can't convert map key to string".to_owned()) .ok_or_else(|| "Can't convert map key to string".to_owned())
.map(|key| (key, &p.1)) .map(|key| (key, &p.1))
}) })
.collect::<Result<HashMap<&str, &Value>, String>>() .collect::<Result<HashMap<&str, &Value>, String>>()
} }