Add dialog for opening project, highlight active file in project menu
This commit is contained in:
parent
0117a7bc02
commit
8dd38517ab
4 changed files with 107 additions and 48 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
|
@ -895,7 +895,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-text"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/pop-os/cosmic-text?branch=vi-editor#c1e40363ab576c90edb7b78f1f257b3845558b1a"
|
||||
source = "git+https://github.com/pop-os/cosmic-text?branch=vi-editor#423fc2243930645036ff053e384a3ce64e70255e"
|
||||
dependencies = [
|
||||
"fontdb 0.15.0",
|
||||
"libm",
|
||||
|
|
@ -5854,18 +5854,18 @@ checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
|
|||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.16"
|
||||
version = "0.7.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c552e97c5a9b90bc8ddc545b5106e798807376356688ebaa3aee36f44f8c4b9e"
|
||||
checksum = "a1808c6e5aa42cb2b67578276190258f08679c275d92a19735aad5d359e1b154"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.16"
|
||||
version = "0.7.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "964bc0588d7ac1c0243d0427ef08482618313702bbb014806cb7ab3da34d3d99"
|
||||
checksum = "ea597733532c780ce3e110401fc3b359b984cc78e17ac0917d3f371ffd1c1618"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
127
src/main.rs
127
src/main.rs
|
|
@ -69,8 +69,10 @@ pub struct App {
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum Message {
|
||||
New,
|
||||
OpenDialog,
|
||||
Open(PathBuf),
|
||||
OpenFileDialog,
|
||||
OpenFile(PathBuf),
|
||||
OpenProjectDialog,
|
||||
OpenProject(PathBuf),
|
||||
Save,
|
||||
TabActivate(segmented_button::Entity),
|
||||
TabClose(segmented_button::Entity),
|
||||
|
|
@ -194,10 +196,34 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn update_title(&mut self) -> Command<Message> {
|
||||
let title = match self.active_tab() {
|
||||
Some(tab) => tab.title(),
|
||||
None => format!("No Open File"),
|
||||
let (title, tab_path_opt) = match self.active_tab() {
|
||||
Some(tab) => (tab.title(), tab.path_opt.clone()),
|
||||
None => (format!("No Open File"), None),
|
||||
};
|
||||
|
||||
//TODO: is this the best place for this?
|
||||
let mut active_id = segmented_button::Entity::default();
|
||||
match tab_path_opt {
|
||||
Some(tab_path) => {
|
||||
for id in self.nav_model.iter() {
|
||||
match self.nav_model.data(id) {
|
||||
Some(node) => match node {
|
||||
ProjectNode::File { path, .. } => {
|
||||
if path == &tab_path {
|
||||
active_id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
self.nav_model.activate(active_id);
|
||||
|
||||
let window_title = format!("{title} - COSMIC Text Editor");
|
||||
self.set_header_title(title.clone());
|
||||
self.set_window_title(window_title)
|
||||
|
|
@ -247,6 +273,10 @@ impl cosmic::Application for App {
|
|||
// Show nav bar only if project is provided
|
||||
if app.core.nav_bar_active() != app.nav_model.iter().next().is_some() {
|
||||
app.core.nav_bar_toggle();
|
||||
app.nav_model
|
||||
.insert()
|
||||
.icon(icon::from_name("folder-open-symbolic").size(16).icon())
|
||||
.text("Open project");
|
||||
}
|
||||
|
||||
// Open an empty file if no arguments provided
|
||||
|
|
@ -263,7 +293,8 @@ impl cosmic::Application for App {
|
|||
}
|
||||
|
||||
fn on_nav_select(&mut self, id: nav_bar::Id) -> Command<Message> {
|
||||
let node = match self.nav_model.data_mut::<ProjectNode>(id) {
|
||||
// Toggle open state and get clone of node data
|
||||
let node_opt = match self.nav_model.data_mut::<ProjectNode>(id) {
|
||||
Some(node) => {
|
||||
match node {
|
||||
ProjectNode::Folder { open, .. } => {
|
||||
|
|
@ -271,43 +302,50 @@ impl cosmic::Application for App {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
node.clone()
|
||||
}
|
||||
None => {
|
||||
log::warn!("no path found for id {:?}", id);
|
||||
return Command::none();
|
||||
Some(node.clone())
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
self.nav_model
|
||||
.icon_set(id, icon::from_name(node.icon_name()).size(16).icon());
|
||||
match node_opt {
|
||||
Some(node) => {
|
||||
// Update icon
|
||||
self.nav_model
|
||||
.icon_set(id, icon::from_name(node.icon_name()).size(16).icon());
|
||||
|
||||
match node {
|
||||
ProjectNode::Folder { path, open, .. } => {
|
||||
let position = self.nav_model.position(id).unwrap_or(0);
|
||||
let indent = self.nav_model.indent(id).unwrap_or(0);
|
||||
if open {
|
||||
self.open_folder(path, position + 1, indent + 1);
|
||||
} else {
|
||||
loop {
|
||||
let child_id = match self.nav_model.entity_at(position + 1) {
|
||||
Some(some) => some,
|
||||
None => break,
|
||||
};
|
||||
|
||||
if self.nav_model.indent(child_id).unwrap_or(0) > indent {
|
||||
self.nav_model.remove(child_id);
|
||||
match node {
|
||||
ProjectNode::Folder { path, open, .. } => {
|
||||
let position = self.nav_model.position(id).unwrap_or(0);
|
||||
let indent = self.nav_model.indent(id).unwrap_or(0);
|
||||
if open {
|
||||
// Open folder
|
||||
self.open_folder(path, position + 1, indent + 1);
|
||||
} else {
|
||||
break;
|
||||
// Close folder
|
||||
loop {
|
||||
let child_id = match self.nav_model.entity_at(position + 1) {
|
||||
Some(some) => some,
|
||||
None => break,
|
||||
};
|
||||
|
||||
if self.nav_model.indent(child_id).unwrap_or(0) > indent {
|
||||
self.nav_model.remove(child_id);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::none()
|
||||
}
|
||||
ProjectNode::File { path, .. } => {
|
||||
//TODO: go to already open file if possible
|
||||
self.update(Message::OpenFile(path))
|
||||
}
|
||||
}
|
||||
Command::none()
|
||||
}
|
||||
ProjectNode::File { path, .. } => {
|
||||
//TODO: go to already open file if possible
|
||||
self.open_tab(Some(path.clone()));
|
||||
self.update_title()
|
||||
None => {
|
||||
// Open project
|
||||
self.update(Message::OpenProjectDialog)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -318,11 +356,11 @@ impl cosmic::Application for App {
|
|||
self.open_tab(None);
|
||||
return self.update_title();
|
||||
}
|
||||
Message::OpenDialog => {
|
||||
Message::OpenFileDialog => {
|
||||
return Command::perform(
|
||||
async {
|
||||
if let Some(handle) = rfd::AsyncFileDialog::new().pick_file().await {
|
||||
message::app(Message::Open(handle.path().to_owned()))
|
||||
message::app(Message::OpenFile(handle.path().to_owned()))
|
||||
} else {
|
||||
message::none()
|
||||
}
|
||||
|
|
@ -330,10 +368,25 @@ impl cosmic::Application for App {
|
|||
|x| x,
|
||||
);
|
||||
}
|
||||
Message::Open(path) => {
|
||||
Message::OpenFile(path) => {
|
||||
self.open_tab(Some(path));
|
||||
return self.update_title();
|
||||
}
|
||||
Message::OpenProjectDialog => {
|
||||
return Command::perform(
|
||||
async {
|
||||
if let Some(handle) = rfd::AsyncFileDialog::new().pick_folder().await {
|
||||
message::app(Message::OpenProject(handle.path().to_owned()))
|
||||
} else {
|
||||
message::none()
|
||||
}
|
||||
},
|
||||
|x| x,
|
||||
);
|
||||
}
|
||||
Message::OpenProject(path) => {
|
||||
self.open_project(path);
|
||||
}
|
||||
Message::Save => {
|
||||
let mut title_opt = None;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ pub fn menu_bar<'a>(config: &Config) -> Element<'a, Message> {
|
|||
menu_key("New file", "Ctrl + N", Message::New),
|
||||
menu_key("New window", "Ctrl + Shift + N", Message::Todo),
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
menu_key("Open file...", "Ctrl + O", Message::OpenDialog),
|
||||
menu_key("Open file...", "Ctrl + O", Message::OpenFileDialog),
|
||||
MenuTree::with_children(
|
||||
menu_folder("Open recent"),
|
||||
vec![menu_item("TODO", Message::Todo)],
|
||||
|
|
|
|||
16
src/tab.rs
16
src/tab.rs
|
|
@ -56,11 +56,17 @@ impl Tab {
|
|||
let mut editor = editor.borrow_with(&mut font_system);
|
||||
match editor.load_text(&path, self.attrs) {
|
||||
Ok(()) => {
|
||||
log::info!("opened '{}'", path.display());
|
||||
self.path_opt = Some(path);
|
||||
log::info!("opened {:?}", path);
|
||||
self.path_opt = match fs::canonicalize(&path) {
|
||||
Ok(ok) => Some(ok),
|
||||
Err(err) => {
|
||||
log::error!("failed to canonicalize {:?}: {}", path, err);
|
||||
Some(path)
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("failed to open '{}': {}", path.display(), err);
|
||||
log::error!("failed to open {:?}: {}", path, err);
|
||||
self.path_opt = None;
|
||||
}
|
||||
}
|
||||
|
|
@ -76,10 +82,10 @@ impl Tab {
|
|||
}
|
||||
match fs::write(path, text) {
|
||||
Ok(()) => {
|
||||
log::info!("saved '{}'", path.display());
|
||||
log::info!("saved {:?}", path);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("failed to save '{}': {}", path.display(), err);
|
||||
log::error!("failed to save {:?}: {}", path, err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue