2017-05-27 16:50:25 +00:00
|
|
|
use std::ops::Deref;
|
2017-05-27 20:51:22 +00:00
|
|
|
use std::rc::Rc;
|
|
|
|
use std::cell::RefCell;
|
2017-05-27 16:50:25 +00:00
|
|
|
|
|
|
|
use gtk;
|
|
|
|
use gtk::prelude::*;
|
|
|
|
|
2017-12-31 09:47:50 +00:00
|
|
|
use glib;
|
2017-05-28 09:29:50 +00:00
|
|
|
use glib::signal;
|
|
|
|
|
2017-09-26 13:59:28 +00:00
|
|
|
use pango;
|
|
|
|
|
2018-03-18 17:45:06 +00:00
|
|
|
use neovim_lib::{NeovimApi, NeovimApiAsync};
|
2017-05-27 16:50:25 +00:00
|
|
|
use neovim_lib::neovim_api::Tabpage;
|
|
|
|
|
2017-07-06 09:41:35 +00:00
|
|
|
use nvim;
|
2017-05-27 20:51:22 +00:00
|
|
|
use nvim::ErrorReport;
|
|
|
|
|
|
|
|
struct State {
|
|
|
|
data: Vec<Tabpage>,
|
2017-05-28 09:29:50 +00:00
|
|
|
selected: Option<Tabpage>,
|
2017-11-10 15:36:54 +00:00
|
|
|
nvim: Option<Rc<nvim::NeovimClient>>,
|
2017-05-27 20:51:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
pub fn new() -> Self {
|
2017-05-28 09:29:50 +00:00
|
|
|
State {
|
2017-05-27 20:51:22 +00:00
|
|
|
data: Vec::new(),
|
2017-05-28 09:29:50 +00:00
|
|
|
selected: None,
|
2017-05-27 20:51:22 +00:00
|
|
|
nvim: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-28 09:29:50 +00:00
|
|
|
fn switch_page(&self, idx: u32) {
|
|
|
|
let target = &self.data[idx as usize];
|
|
|
|
if Some(target) != self.selected.as_ref() {
|
2017-11-11 15:56:23 +00:00
|
|
|
if let Some(mut nvim) = self.nvim.as_ref().unwrap().nvim() {
|
2017-12-11 20:15:17 +00:00
|
|
|
nvim.set_current_tabpage(target).report_err();
|
2017-11-10 15:36:54 +00:00
|
|
|
}
|
2017-05-28 09:29:50 +00:00
|
|
|
}
|
2017-05-27 20:51:22 +00:00
|
|
|
}
|
2018-02-24 17:01:17 +00:00
|
|
|
|
|
|
|
fn close_tab(&self, idx: u32) {
|
|
|
|
if let Some(mut nvim) = self.nvim.as_ref().unwrap().nvim() {
|
2018-03-18 17:45:06 +00:00
|
|
|
nvim.command_async(&format!(":tabc {}", idx + 1))
|
|
|
|
.cb(|r| r.report_err())
|
|
|
|
.call();
|
2018-02-24 17:01:17 +00:00
|
|
|
}
|
|
|
|
}
|
2017-05-27 20:51:22 +00:00
|
|
|
}
|
|
|
|
|
2017-05-27 16:50:25 +00:00
|
|
|
pub struct Tabline {
|
|
|
|
tabs: gtk::Notebook,
|
2017-05-27 20:51:22 +00:00
|
|
|
state: Rc<RefCell<State>>,
|
2017-12-31 09:47:50 +00:00
|
|
|
switch_handler_id: glib::SignalHandlerId,
|
2017-05-27 16:50:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Tabline {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
let tabs = gtk::Notebook::new();
|
|
|
|
|
|
|
|
tabs.set_can_focus(false);
|
|
|
|
tabs.set_scrollable(true);
|
|
|
|
tabs.set_show_border(false);
|
|
|
|
tabs.set_border_width(0);
|
2018-02-24 17:01:17 +00:00
|
|
|
tabs.set_hexpand(true);
|
2017-05-27 20:51:22 +00:00
|
|
|
tabs.hide();
|
|
|
|
|
|
|
|
let state = Rc::new(RefCell::new(State::new()));
|
|
|
|
|
|
|
|
let state_ref = state.clone();
|
2017-05-28 09:29:50 +00:00
|
|
|
let switch_handler_id =
|
|
|
|
tabs.connect_switch_page(move |_, _, idx| state_ref.borrow().switch_page(idx));
|
2017-05-27 16:50:25 +00:00
|
|
|
|
2017-05-28 09:29:50 +00:00
|
|
|
Tabline {
|
2017-05-27 16:50:25 +00:00
|
|
|
tabs,
|
2017-05-27 20:51:22 +00:00
|
|
|
state,
|
2017-05-28 09:29:50 +00:00
|
|
|
switch_handler_id,
|
2017-05-27 16:50:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-26 13:59:28 +00:00
|
|
|
fn update_state(
|
|
|
|
&self,
|
2017-11-10 15:36:54 +00:00
|
|
|
nvim: &Rc<nvim::NeovimClient>,
|
2017-09-26 13:59:28 +00:00
|
|
|
selected: &Tabpage,
|
|
|
|
tabs: &[(Tabpage, Option<String>)],
|
|
|
|
) {
|
2017-05-28 09:29:50 +00:00
|
|
|
let mut state = self.state.borrow_mut();
|
|
|
|
|
|
|
|
if state.nvim.is_none() {
|
|
|
|
state.nvim = Some(nvim.clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
state.selected = Some(selected.clone());
|
|
|
|
|
|
|
|
state.data = tabs.iter().map(|item| item.0.clone()).collect();
|
|
|
|
}
|
|
|
|
|
2017-09-26 13:59:28 +00:00
|
|
|
pub fn update_tabs(
|
|
|
|
&self,
|
2017-11-10 15:36:54 +00:00
|
|
|
nvim: &Rc<nvim::NeovimClient>,
|
2017-09-26 13:59:28 +00:00
|
|
|
selected: &Tabpage,
|
|
|
|
tabs: &[(Tabpage, Option<String>)],
|
|
|
|
) {
|
2017-05-27 20:51:22 +00:00
|
|
|
if tabs.len() <= 1 {
|
|
|
|
self.tabs.hide();
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
self.tabs.show();
|
|
|
|
}
|
|
|
|
|
2017-05-28 09:29:50 +00:00
|
|
|
self.update_state(nvim, selected, tabs);
|
2017-05-27 20:51:22 +00:00
|
|
|
|
2017-05-28 09:29:50 +00:00
|
|
|
|
2017-12-31 09:47:50 +00:00
|
|
|
signal::signal_handler_block(&self.tabs, &self.switch_handler_id);
|
2017-05-27 20:51:22 +00:00
|
|
|
|
2017-05-27 16:50:25 +00:00
|
|
|
let count = self.tabs.get_n_pages() as usize;
|
|
|
|
if count < tabs.len() {
|
|
|
|
for _ in count..tabs.len() {
|
|
|
|
let empty = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
|
|
|
empty.show_all();
|
2017-09-26 13:59:28 +00:00
|
|
|
let title = gtk::Label::new(None);
|
|
|
|
title.set_ellipsize(pango::EllipsizeMode::Middle);
|
|
|
|
title.set_width_chars(25);
|
2018-02-24 17:01:17 +00:00
|
|
|
let close_btn = gtk::Button::new_from_icon_name(
|
|
|
|
"window-close-symbolic",
|
|
|
|
gtk::IconSize::Menu.into(),
|
|
|
|
);
|
|
|
|
close_btn.set_relief(gtk::ReliefStyle::None);
|
|
|
|
close_btn.get_style_context().unwrap().add_class("small-button");
|
|
|
|
close_btn.set_focus_on_click(false);
|
|
|
|
let label_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
|
|
|
label_box.pack_start(&title, true, false, 0);
|
|
|
|
label_box.pack_start(&close_btn, false, false, 0);
|
|
|
|
title.show();
|
|
|
|
close_btn.show();
|
|
|
|
self.tabs.append_page(&empty, Some(&label_box));
|
|
|
|
|
|
|
|
let tabs = self.tabs.clone();
|
|
|
|
let state_ref = Rc::clone(&self.state);
|
|
|
|
close_btn.connect_clicked(move |btn| {
|
|
|
|
let current_label = btn
|
|
|
|
.get_parent().unwrap();
|
|
|
|
for i in 0..tabs.get_n_pages() {
|
|
|
|
let page = tabs.get_nth_page(Some(i)).unwrap();
|
|
|
|
let label = tabs.get_tab_label(&page).unwrap();
|
|
|
|
if label == current_label {
|
|
|
|
state_ref.borrow().close_tab(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2017-05-27 16:50:25 +00:00
|
|
|
}
|
2017-05-28 09:29:50 +00:00
|
|
|
} else if count > tabs.len() {
|
2017-05-27 16:50:25 +00:00
|
|
|
for _ in tabs.len()..count {
|
|
|
|
self.tabs.remove_page(None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (idx, tab) in tabs.iter().enumerate() {
|
|
|
|
let tab_child = self.tabs.get_nth_page(Some(idx as u32));
|
2017-09-26 13:59:28 +00:00
|
|
|
let tab_label = self.tabs
|
|
|
|
.get_tab_label(&tab_child.unwrap())
|
|
|
|
.unwrap()
|
2018-02-24 17:01:17 +00:00
|
|
|
.downcast::<gtk::Box>()
|
|
|
|
.unwrap()
|
|
|
|
.get_children()
|
|
|
|
.into_iter()
|
|
|
|
.next()
|
|
|
|
.unwrap()
|
2017-09-26 13:59:28 +00:00
|
|
|
.downcast::<gtk::Label>()
|
|
|
|
.unwrap();
|
|
|
|
tab_label.set_text(tab.1.as_ref().unwrap_or(&"??".to_owned()));
|
2017-05-27 20:51:22 +00:00
|
|
|
|
|
|
|
if *selected == tab.0 {
|
|
|
|
self.tabs.set_current_page(Some(idx as u32));
|
|
|
|
}
|
2017-05-27 16:50:25 +00:00
|
|
|
}
|
2017-05-28 09:29:50 +00:00
|
|
|
|
2017-12-31 09:47:50 +00:00
|
|
|
signal::signal_handler_unblock(&self.tabs, &self.switch_handler_id);
|
2017-05-27 16:50:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Deref for Tabline {
|
|
|
|
type Target = gtk::Notebook;
|
|
|
|
|
|
|
|
fn deref(&self) -> >k::Notebook {
|
|
|
|
&self.tabs
|
|
|
|
}
|
|
|
|
}
|