Add dialog for opening project, highlight active file in project menu

This commit is contained in:
Jeremy Soller 2023-10-27 13:41:48 -06:00
parent 0117a7bc02
commit 8dd38517ab
No known key found for this signature in database
GPG key ID: DCFCA852D3906975
4 changed files with 107 additions and 48 deletions

10
Cargo.lock generated
View file

@ -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",

View file

@ -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;

View file

@ -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)],

View file

@ -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 {