mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-23 06:05:24 +00:00
WIP: Epiphany Refactor (#85)
This commit is contained in:
committed by
GitHub
parent
80b9b7594b
commit
72bc77f1d5
@@ -1,306 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use file_route::FileRoute;
|
||||
use id::{Id, get_id};
|
||||
use message_session::{Message, MessageSession};
|
||||
use partition::Partition;
|
||||
use project::Project;
|
||||
use rbx::{RbxInstance, RbxTree, RbxValue};
|
||||
use vfs_session::{VfsSession, FileItem, FileChange};
|
||||
|
||||
static SERVICES: &'static [&'static str] = &[
|
||||
"Chat",
|
||||
"Lighting",
|
||||
"LocalizationService",
|
||||
"Players",
|
||||
"ReplicatedFirst",
|
||||
"ReplicatedStorage",
|
||||
"ServerScriptService",
|
||||
"ServerStorage",
|
||||
"SoundService",
|
||||
"StarterGui",
|
||||
"StarterPack",
|
||||
"StarterPlayer",
|
||||
"TestService",
|
||||
"Workspace",
|
||||
];
|
||||
|
||||
fn get_partition_target_class_name(target: &[String]) -> &'static str {
|
||||
match target.len() {
|
||||
1 => {
|
||||
let target_name = &target[0];
|
||||
|
||||
for &service in SERVICES {
|
||||
if service == target_name {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
||||
"Folder"
|
||||
},
|
||||
2 => {
|
||||
"Folder"
|
||||
},
|
||||
_ => "Folder",
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rethink data structure and insertion/update behavior. Maybe break some
|
||||
// pieces off into a new object?
|
||||
fn file_to_instances(
|
||||
file_item: &FileItem,
|
||||
partition: &Partition,
|
||||
tree: &mut RbxTree,
|
||||
instances_by_route: &mut HashMap<FileRoute, Id>,
|
||||
parent_id: Option<Id>,
|
||||
) -> (Id, Vec<Id>) {
|
||||
match file_item {
|
||||
FileItem::File { contents, route } => {
|
||||
let primary_id = match instances_by_route.get(&file_item.get_route()) {
|
||||
Some(&id) => id,
|
||||
None => {
|
||||
let id = get_id();
|
||||
instances_by_route.insert(route.clone(), id);
|
||||
|
||||
id
|
||||
},
|
||||
};
|
||||
|
||||
// This is placeholder logic; this whole function is!
|
||||
let (class_name, property_key, name) = {
|
||||
let file_name = match route.route.last() {
|
||||
Some(v) => v.to_string(),
|
||||
None => partition.path.file_name().unwrap().to_str().unwrap().to_string()
|
||||
};
|
||||
|
||||
let use_partition_name = route.route.len() == 0;
|
||||
|
||||
let partition_name = partition.target.last().unwrap();
|
||||
|
||||
fn strip_suffix<'a>(source: &'a str, suffix: &'static str) -> String {
|
||||
source[..source.len() - suffix.len()].to_string()
|
||||
}
|
||||
|
||||
if file_name.ends_with(".client.lua") {
|
||||
let name = if use_partition_name {
|
||||
partition_name.clone()
|
||||
} else {
|
||||
strip_suffix(&file_name, ".client.lua")
|
||||
};
|
||||
|
||||
("LocalScript", "Source", name)
|
||||
} else if file_name.ends_with(".server.lua") {
|
||||
let name = if use_partition_name {
|
||||
partition_name.clone()
|
||||
} else {
|
||||
strip_suffix(&file_name, ".server.lua")
|
||||
};
|
||||
|
||||
("Script", "Source", name)
|
||||
} else if file_name.ends_with(".lua") {
|
||||
let name = if use_partition_name {
|
||||
partition_name.clone()
|
||||
} else {
|
||||
strip_suffix(&file_name, ".lua")
|
||||
};
|
||||
|
||||
("ModuleScript", "Source", name)
|
||||
} else {
|
||||
let name = if use_partition_name {
|
||||
partition_name.clone()
|
||||
} else {
|
||||
file_name
|
||||
};
|
||||
|
||||
// TODO: Error/warn/skip instead of falling back
|
||||
("StringValue", "Value", name)
|
||||
}
|
||||
};
|
||||
|
||||
let mut properties = HashMap::new();
|
||||
properties.insert(property_key.to_string(), RbxValue::String { value: contents.clone() });
|
||||
|
||||
tree.insert_instance(primary_id, RbxInstance {
|
||||
name,
|
||||
class_name: class_name.to_string(),
|
||||
properties,
|
||||
children: Vec::new(),
|
||||
parent: parent_id,
|
||||
});
|
||||
|
||||
(primary_id, vec![primary_id])
|
||||
},
|
||||
FileItem::Directory { children, route } => {
|
||||
let primary_id = match instances_by_route.get(&file_item.get_route()) {
|
||||
Some(&id) => id,
|
||||
None => {
|
||||
let id = get_id();
|
||||
instances_by_route.insert(route.clone(), id);
|
||||
|
||||
id
|
||||
},
|
||||
};
|
||||
|
||||
let mut child_ids = Vec::new();
|
||||
|
||||
let mut changed_ids = vec![primary_id];
|
||||
|
||||
for child_file_item in children.values() {
|
||||
let (child_id, mut child_changed_ids) = file_to_instances(child_file_item, partition, tree, instances_by_route, Some(primary_id));
|
||||
|
||||
child_ids.push(child_id);
|
||||
changed_ids.push(child_id);
|
||||
|
||||
// TODO: Should I stop using drain on Vecs of Copyable types?
|
||||
for id in child_changed_ids.drain(..) {
|
||||
changed_ids.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
let class_name = get_partition_target_class_name(&route.route).to_string();
|
||||
|
||||
let name = if route.route.len() == 0 {
|
||||
partition.target.last().unwrap().clone()
|
||||
} else {
|
||||
route.file_name(partition)
|
||||
};
|
||||
|
||||
tree.insert_instance(primary_id, RbxInstance {
|
||||
name,
|
||||
class_name,
|
||||
properties: HashMap::new(),
|
||||
children: child_ids,
|
||||
parent: parent_id,
|
||||
});
|
||||
|
||||
(primary_id, changed_ids)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RbxSession {
|
||||
project: Project,
|
||||
|
||||
vfs_session: Arc<RwLock<VfsSession>>,
|
||||
|
||||
message_session: MessageSession,
|
||||
|
||||
/// The RbxInstance that represents each partition.
|
||||
// TODO: Can this be removed in favor of instances_by_route?
|
||||
pub partition_instances: HashMap<String, Id>,
|
||||
|
||||
/// Keeps track of all of the instances in the tree
|
||||
pub tree: RbxTree,
|
||||
|
||||
/// A map from files in the VFS to instances loaded in the session.
|
||||
instances_by_route: HashMap<FileRoute, Id>,
|
||||
}
|
||||
|
||||
impl RbxSession {
|
||||
pub fn new(project: Project, vfs_session: Arc<RwLock<VfsSession>>, message_session: MessageSession) -> RbxSession {
|
||||
RbxSession {
|
||||
project,
|
||||
vfs_session,
|
||||
message_session,
|
||||
partition_instances: HashMap::new(),
|
||||
tree: RbxTree::new(),
|
||||
instances_by_route: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_partitions(&mut self) {
|
||||
let vfs_session_arc = self.vfs_session.clone();
|
||||
let vfs_session = vfs_session_arc.read().unwrap();
|
||||
|
||||
for partition in self.project.partitions.values() {
|
||||
let route = FileRoute {
|
||||
partition: partition.name.clone(),
|
||||
route: Vec::new(),
|
||||
};
|
||||
let file_item = vfs_session.get_by_route(&route).unwrap();
|
||||
|
||||
let parent_id = match route.parent() {
|
||||
Some(parent_route) => match self.instances_by_route.get(&parent_route) {
|
||||
Some(&parent_id) => Some(parent_id),
|
||||
None => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let (root_id, _) = file_to_instances(file_item, partition, &mut self.tree, &mut self.instances_by_route, parent_id);
|
||||
|
||||
self.partition_instances.insert(partition.name.clone(), root_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_change(&mut self, change: &FileChange) {
|
||||
let vfs_session_arc = self.vfs_session.clone();
|
||||
let vfs_session = vfs_session_arc.read().unwrap();
|
||||
|
||||
match change {
|
||||
FileChange::Created(route) | FileChange::Updated(route) => {
|
||||
let file_item = vfs_session.get_by_route(route).unwrap();
|
||||
let partition = self.project.partitions.get(&route.partition).unwrap();
|
||||
|
||||
let parent_id = match route.parent() {
|
||||
Some(parent_route) => match self.instances_by_route.get(&parent_route) {
|
||||
Some(&parent_id) => Some(parent_id),
|
||||
None => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let (_, changed_ids) = file_to_instances(file_item, partition, &mut self.tree, &mut self.instances_by_route, parent_id);
|
||||
|
||||
let messages = changed_ids
|
||||
.iter()
|
||||
.map(|&id| Message::InstanceChanged { id })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.message_session.push_messages(&messages);
|
||||
},
|
||||
FileChange::Deleted(route) => {
|
||||
match self.instances_by_route.get(route) {
|
||||
Some(&id) => {
|
||||
self.tree.delete_instance(id);
|
||||
self.instances_by_route.remove(route);
|
||||
self.message_session.push_messages(&[Message::InstanceChanged { id }]);
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
},
|
||||
FileChange::Moved(from_route, to_route) => {
|
||||
let mut messages = Vec::new();
|
||||
|
||||
match self.instances_by_route.get(from_route) {
|
||||
Some(&id) => {
|
||||
self.tree.delete_instance(id);
|
||||
self.instances_by_route.remove(from_route);
|
||||
messages.push(Message::InstanceChanged { id });
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
|
||||
let file_item = vfs_session.get_by_route(to_route).unwrap();
|
||||
let partition = self.project.partitions.get(&to_route.partition).unwrap();
|
||||
|
||||
let parent_id = match to_route.parent() {
|
||||
Some(parent_route) => match self.instances_by_route.get(&parent_route) {
|
||||
Some(&parent_id) => Some(parent_id),
|
||||
None => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let (_, changed_ids) = file_to_instances(file_item, partition, &mut self.tree, &mut self.instances_by_route, parent_id);
|
||||
|
||||
for id in changed_ids {
|
||||
messages.push(Message::InstanceChanged { id });
|
||||
}
|
||||
|
||||
self.message_session.push_messages(&messages);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user