Wip/wdanilo/widgets 182746060 (#3678)

This commit is contained in:
Wojciech Daniło 2022-10-04 04:51:27 +02:00 committed by GitHub
parent 0d74ab6124
commit 61546a7ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
322 changed files with 10529 additions and 5843 deletions

70
Cargo.lock generated
View File

@ -936,6 +936,12 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c"
[[package]]
name = "bytemuck"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da"
[[package]]
name = "byteorder"
version = "1.4.3"
@ -2246,6 +2252,7 @@ dependencies = [
"enso-web",
"failure",
"futures 0.3.21",
"gen-iter",
"ifmt",
"itertools 0.10.3",
"lazy_static",
@ -2493,7 +2500,6 @@ dependencies = [
"enso-types",
"enso-web",
"ensogl-text-embedded-fonts",
"ensogl-text-msdf",
"enum_dispatch",
"failure",
"itertools 0.10.3",
@ -2608,17 +2614,6 @@ dependencies = [
"web-sys",
]
[[package]]
name = "ensogl-example-glyph-system"
version = "0.1.0"
dependencies = [
"ensogl-core",
"ensogl-text",
"ensogl-text-embedded-fonts",
"ensogl-text-msdf",
"wasm-bindgen",
]
[[package]]
name = "ensogl-example-grid-view"
version = "0.1.0"
@ -2775,7 +2770,6 @@ dependencies = [
"ensogl-example-dom-symbols",
"ensogl-example-drop-manager",
"ensogl-example-easing-animator",
"ensogl-example-glyph-system",
"ensogl-example-grid-view",
"ensogl-example-list-view",
"ensogl-example-mouse-events",
@ -2942,6 +2936,7 @@ dependencies = [
"ensogl-text-msdf",
"ordered-float",
"owned_ttf_parser",
"rustybuzz",
"serde",
"wasm-bindgen-test",
"xi-rope",
@ -2975,6 +2970,7 @@ dependencies = [
"enso-build-utilities",
"enso-prelude",
"enso-types",
"enso-web",
"ensogl-text-embedded-fonts",
"ensogl-text-font-family",
"failure",
@ -3340,6 +3336,12 @@ dependencies = [
"enso-prelude",
]
[[package]]
name = "gen-iter"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1668ac3c7b8cc5f1e31565ed509d8d70aa1a81bd7f508b620725b78c6e1d7049"
[[package]]
name = "generic-array"
version = "0.12.4"
@ -3820,7 +3822,7 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5617e92fc2f2501c3e2bc6ce547cad841adba2bae5b921c7e52510beca6d084c"
dependencies = [
"base64 0.11.0",
"base64 0.13.0",
"bytes 1.1.0",
"http",
"httpdate 1.0.2",
@ -5956,6 +5958,22 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "rustybuzz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a617c811f5c9a7060fe511d35d13bf5b9f0463ce36d63ce666d05779df2b4eba"
dependencies = [
"bitflags",
"bytemuck",
"smallvec 1.8.0",
"ttf-parser",
"unicode-bidi-mirroring",
"unicode-ccc",
"unicode-general-category",
"unicode-script",
]
[[package]]
name = "ryu"
version = "1.0.10"
@ -7162,6 +7180,24 @@ version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-bidi-mirroring"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694"
[[package]]
name = "unicode-ccc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
[[package]]
name = "unicode-general-category"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742"
[[package]]
name = "unicode-ident"
version = "1.0.0"
@ -7177,6 +7213,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-script"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58dd944fd05f2f0b5c674917aea8a4df6af84f2d8de3fe8d988b95d28fb8fb09"
[[package]]
name = "unicode-segmentation"
version = "1.9.0"

View File

@ -3,6 +3,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]
#![warn(trivial_casts)]

View File

@ -3,6 +3,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]

View File

@ -9,6 +9,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]
#![warn(trivial_casts)]

View File

@ -1,7 +1,7 @@
//! Code for module-level double representation processing.
use crate::prelude::*;
use enso_text::unit::*;
use enso_text::index::*;
use crate::alias_analysis;
use crate::definition;
@ -828,7 +828,7 @@ pub fn lookup_method(
pub fn definition_span(
ast: &known::Module,
id: &definition::Id,
) -> FallibleResult<enso_text::Range<Bytes>> {
) -> FallibleResult<enso_text::Range<Byte>> {
let location = locate(ast, id)?;
ast.range_of_descendant_at(&location.crumbs)
}

View File

@ -403,7 +403,6 @@ mod tests {
impl Case {
fn run(&self, parser: &Parser) {
let logger = DefaultTraceLogger::new("Collapsing_Test");
let ast = parser.parse_module(self.initial_method_code, default()).unwrap();
let main = module::locate_child(&ast, &self.refactored_name).unwrap();
let graph = graph::GraphInfo::from_definition(main.item.clone());
@ -417,14 +416,14 @@ mod tests {
let new_method = collapsed.new_method.ast(0, parser).unwrap();
let placement = module::Placement::Before(self.refactored_name.clone());
let new_main = &collapsed.updated_definition.ast;
info!(logger, "Generated method:\n{new_method}");
info!(logger, "Updated method:\n{new_method}");
info!("Generated method:\n{new_method}");
info!("Updated method:\n{new_method}");
let mut module = module::Info { ast: ast.clone_ref() };
let main_crumb = Crumb::from(main.crumb());
module.ast = module.ast.set(&main_crumb, new_main.ast().clone()).unwrap();
module.add_method(collapsed.new_method, placement, parser).unwrap();
ast::test_utils::assert_unique_ids(module.ast.as_ref());
info!(logger, "Updated method:\n{&module.ast}");
info!("Updated method:\n{}", &module.ast);
assert_eq!(new_method.repr(), self.expected_generated);
assert_eq!(new_main.repr(), self.expected_refactored);
};

View File

@ -1,6 +1,7 @@
//! A module with functions used to support working with text representation of the language.
use crate::prelude::*;
use enso_text::index::*;
use enso_text::unit::*;
use ast::IdMap;
@ -14,7 +15,7 @@ use ast::IdMap;
/// Update IdMap to reflect the recent code change.
pub fn apply_code_change_to_id_map(
id_map: &mut IdMap,
change: &enso_text::text::Change<Bytes, String>,
change: &enso_text::text::Change<Byte, String>,
code: &str,
) {
// TODO [mwu]
@ -29,27 +30,26 @@ pub fn apply_code_change_to_id_map(
let inserted = change.text.as_str();
let new_code = change.applied(code).unwrap_or_else(|_| code.to_owned());
let non_white = |c: char| !c.is_whitespace();
let logger = enso_logger::DefaultWarningLogger::new("apply_code_change_to_id_map");
let vector = &mut id_map.vec;
let inserted_size: Bytes = inserted.len().into();
let inserted_size: ByteDiff = inserted.len().into();
info!(logger, "Old code:\n```\n{code}\n```");
info!(logger, "New code:\n```\n{new_code}\n```");
info!(logger, "Updating the ID map with the following text edit: {change:?}.");
info!("Old code:\n```\n{code}\n```");
info!("New code:\n```\n{new_code}\n```");
info!("Updating the ID map with the following text edit: {change:?}.");
// Remove all entries fully covered by the removed span.
vector.drain_filter(|(range, _)| removed.contains_range(range));
// If the edited section ends up being the trailing part of AST node, how many bytes should be
// trimmed from the id. Precalculated, as is constant in the loop below.
let to_trim_back: Bytes = {
let to_trim_back: ByteDiff = {
let last_non_white = inserted.rfind(non_white);
let inserted_len = || inserted.len();
let length_to_last_non_white = |index| inserted.len() - index - 1;
last_non_white.map_or_else(inserted_len, length_to_last_non_white).into()
};
// As above but for the front side.
let to_trim_front: Bytes = {
let to_trim_front: ByteDiff = {
let first_non_white = inserted.find(non_white);
first_non_white.unwrap_or(inserted.len()).into()
};
@ -62,31 +62,31 @@ pub fn apply_code_change_to_id_map(
// This is needed for edits like: `foo f` => `foo` — the earlier `foo` in `foo f` also has a
// id map entry, however we want it to be consistently shadowed by the id from the whole App
// expression.
let mut preferred: HashMap<enso_text::Range<Bytes>, ast::Id> = default();
let mut preferred: HashMap<enso_text::Range<Byte>, ast::Id> = default();
for (range, id) in vector.iter_mut() {
let mut trim_front = false;
let mut trim_back = false;
let initial_range = *range;
info!(logger, "Processing @{range}: `{&code[*range]}`.");
info!("Processing @{range}: `{}`.", &code[*range]);
if range.start > removed.end {
debug!(logger, "Node after the edited region.");
debug!("Node after the edited region.");
// AST node starts after edited region — it will be simply shifted.
let between_range: enso_text::Range<_> = (removed.end..range.start).into();
let between_range: enso_text::Range<Byte> = (removed.end..range.start).into();
let code_between = &code[between_range];
*range = range.moved_left(removed.size()).moved_right(inserted_size);
// If there are only spaces between current AST symbol and insertion, extend the symbol.
// This is for cases like line with `foo ` being changed into `foo j`.
debug!(logger, "Between: `{code_between}`.");
debug!("Between: `{code_between}`.");
if all_spaces(code_between) && inserted_non_white {
debug!(logger, "Will extend the node leftwards.");
debug!("Will extend the node leftwards.");
range.start -= inserted_size + between_range.size();
trim_front = true;
}
} else if range.start >= removed.start {
// AST node starts inside the edited region. It does not have to end inside it.
debug!(logger, "Node overlapping with the end of the edited region.");
debug!("Node overlapping with the end of the edited region.");
let removed_before = range.start - removed.start;
*range = range.moved_left(removed_before);
range.end -= removed.size() - removed_before;
@ -94,7 +94,7 @@ pub fn apply_code_change_to_id_map(
trim_front = true;
} else if range.end >= removed.start {
// AST node starts before the edited region and reaches (or possibly goes past) its end.
debug!(logger, "Node overlapping with the beginning of the edited region.");
debug!("Node overlapping with the beginning of the edited region.");
if range.end <= removed.end {
trim_back = true;
}
@ -102,35 +102,35 @@ pub fn apply_code_change_to_id_map(
range.end -= removed_chars;
range.end += inserted_size;
} else {
debug!(logger, "Node before the edited region.");
debug!("Node before the edited region.");
// If there are only spaces between current AST symbol and insertion, extend the symbol.
// This is for cases like line with `foo ` being changed into `foo j`.
let between_range: enso_text::Range<_> = (range.end..removed.start).into();
let between_range: enso_text::Range<Byte> = (range.end..removed.start).into();
let between = &code[between_range];
if all_spaces(between) && inserted_non_white {
debug!(logger, "Will extend ");
debug!("Will extend ");
range.end += between_range.size() + inserted_size;
trim_back = true;
}
}
if trim_front && to_trim_front > 0.bytes() {
if trim_front && to_trim_front > 0.byte_diff() {
range.start += to_trim_front;
debug!(logger, "Trimming front {to_trim_front.as_usize()} chars.");
debug!("Trimming front {} chars.", to_trim_front.as_usize());
}
if trim_back {
if to_trim_back > 0.bytes() {
if to_trim_back > 0.byte_diff() {
range.end += -to_trim_back;
debug!(logger, "Trimming back {to_trim_back.as_usize()} chars.");
debug!("Trimming back {} chars.", to_trim_back.as_usize());
}
let new_repr = &new_code[*range];
// Trim trailing spaces
let space_count = spaces_size(new_repr.chars().rev());
let spaces_len: Bytes = (space_count.as_usize() * ' '.len_utf8()).into();
if spaces_len > 0.bytes() {
debug!(logger, "Additionally trimming {space_count.as_usize()} trailing spaces.");
debug!(logger, "The would-be code: `{new_repr}`.");
let spaces_len: ByteDiff = (space_count.value * ' '.len_utf8()).into();
if spaces_len > 0.byte_diff() {
debug!("Additionally trimming {} trailing spaces.", space_count);
debug!("The would-be code: `{new_repr}`.");
range.end -= spaces_len;
}
}
@ -141,14 +141,12 @@ pub fn apply_code_change_to_id_map(
preferred.insert(*range, *id);
}
info!(logger, || {
let old_fragment = &code[initial_range];
let new_fragment = &new_code[*range];
iformat!(
"Processing for id {id}: {initial_range} ->\t{range}.\n
let old_fragment = &code[initial_range];
let new_fragment = &new_code[*range];
info!(
"Processing for id {id}: {initial_range} ->\t{range}.\n
Code: `{old_fragment}` => `{new_fragment}`"
)
});
);
}
// If non-preferred entry collides with the preferred one, remove the former.
@ -164,7 +162,7 @@ pub fn apply_code_change_to_id_map(
// ===============
/// Returns the chars count of leading space characters sequence.
fn spaces_size(itr: impl Iterator<Item = char>) -> Chars {
fn spaces_size(itr: impl Iterator<Item = char>) -> Utf16CodeUnit {
itr.take_while(|c| *c == ' ').fold(0, |acc, _| acc + 1).into()
}
@ -198,7 +196,7 @@ mod test {
/// The initial enso program code.
pub code: String,
/// The edit made to the initial code.
pub change: enso_text::Change<Bytes, String>,
pub change: enso_text::Change<Byte, String>,
}
impl Case {
@ -291,13 +289,13 @@ mod test {
let case = Case::from_markdown("foo«aa⎀bb»c");
assert_eq!(case.code, "fooaac");
assert_eq!(case.change.text, "bb");
assert_eq!(case.change.range, 3.bytes()..5.bytes());
assert_eq!(case.change.range, 3.byte()..5.byte());
assert_eq!(case.resulting_code(), "foobbc");
let case = Case::from_markdown("foo«aa»c");
assert_eq!(case.code, "fooaac");
assert_eq!(case.change.text, "");
assert_eq!(case.change.range, 3.bytes()..5.bytes());
assert_eq!(case.change.range, 3.byte()..5.byte());
assert_eq!(case.resulting_code(), "fooc");
}

View File

@ -1,6 +1,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]

View File

@ -12,6 +12,7 @@ chrono = { version = "0.4", features = ["serde"] }
enso-data-structures = { path = "../../../../lib/rust/data-structures" }
enso-logger = { path = "../../../../lib/rust/logger" }
enso-prelude = { path = "../../../../lib/rust/prelude", features = [
"serde",
"serde_json"
] }
enso-shapely = { path = "../../../../lib/rust/shapely" }

View File

@ -113,7 +113,6 @@ impl Client {
/// Function that does early processing of the peer's message and decides how it shall be
/// handled. Returns a function so that it may be passed to the `Handler`.
fn processor(
logger: Logger,
) -> impl FnMut(TransportEvent) -> Disposition<Uuid, FromServerPayloadOwned, Notification> + 'static
{
move |event: TransportEvent| {
@ -125,7 +124,7 @@ impl Client {
Ok(message) => message,
Err(e) => return Disposition::error(e),
};
debug!(logger, "Deserialized incoming binary message: {message:?}");
debug!("Deserialized incoming binary message: {message:?}");
let correlation_id = message.correlation_id;
match message.0.payload {
FromServerPayloadOwned::VisualizationUpdate { context, data } =>
@ -149,7 +148,7 @@ impl Client {
/// * `init` must be called or it needs to be wrapped into `Connection`.
pub fn new(parent: impl AnyLogger, transport: impl Transport + 'static) -> Client {
let logger = Logger::new_sub(parent, "binary-protocol-client");
let processor = Self::processor(logger.clone_ref());
let processor = Self::processor();
Client { logger: logger.clone_ref(), handler: Handler::new(transport, logger, processor) }
}
@ -167,10 +166,8 @@ impl Client {
{
let message = MessageToServerRef::new(payload);
let id = message.message_id;
let logger = self.logger.clone_ref();
let completer = move |reply| {
info!(logger, "Completing request {id} with a reply: {reply:?}");
info!("Completing request {id} with a reply: {reply:?}");
if let FromServerPayloadOwned::Error { code, message, data } = reply {
let code = code as i64;
let error = json_rpc::messages::Error { code, message, data };
@ -193,19 +190,19 @@ impl Client {
impl API for Client {
fn init(&self, client_id: Uuid) -> StaticBoxFuture<FallibleResult> {
info!(self.logger, "Initializing binary connection as client with id {client_id}.");
info!("Initializing binary connection as client with id {client_id}.");
let payload = ToServerPayload::InitSession { client_id };
self.make_request(payload, Self::expect_success)
}
fn write_file(&self, path: &Path, contents: &[u8]) -> StaticBoxFuture<FallibleResult> {
info!(self.logger, "Writing file {path} with {contents.len()} bytes.");
info!("Writing file {} with {} bytes.", path, contents.len());
let payload = ToServerPayload::WriteFile { path, contents };
self.make_request(payload, Self::expect_success)
}
fn read_file(&self, path: &Path) -> StaticBoxFuture<FallibleResult<Vec<u8>>> {
info!(self.logger, "Reading file {path}.");
info!("Reading file {path}.");
let payload = ToServerPayload::ReadFile { path };
self.make_request(payload, move |result| {
if let FromServerPayloadOwned::FileContentsReply { contents } = result {
@ -223,7 +220,7 @@ impl API for Client {
overwrite: bool,
bytes: &[u8],
) -> StaticBoxFuture<FallibleResult<Sha3_224>> {
info!(self.logger, "Writing {bytes.len()} bytes to {path} at offset {byte_offset}");
info!("Writing {} bytes to {path} at offset {byte_offset}", bytes.len());
let payload = ToServerPayload::WriteBytes { path, byte_offset, overwrite, bytes };
self.make_request(payload, move |result| {
if let FromServerPayloadOwned::WriteBytesReply { checksum } = result {

View File

@ -12,10 +12,10 @@ use futures::channel::oneshot;
/// their answer.
/// `Id` identifies the request.
/// `Reply` represents the answer.
#[derive(Debug)]
#[derive(Debug, Derivative)]
#[derivative(Default(bound = ""))]
pub struct OngoingCalls<Id, Reply>
where Id: Hash + Eq {
logger: Logger,
ongoing_calls: HashMap<Id, oneshot::Sender<Reply>>,
}
@ -23,11 +23,8 @@ impl<Id, Reply> OngoingCalls<Id, Reply>
where Id: Copy + Debug + Display + Hash + Eq + Send + Sync + 'static
{
/// Creates a new, empty ongoing request storage.
pub fn new(parent: impl AnyLogger) -> OngoingCalls<Id, Reply> {
OngoingCalls {
logger: Logger::new_sub(parent, "ongoing_calls"),
ongoing_calls: HashMap::new(),
}
pub fn new() -> OngoingCalls<Id, Reply> {
default()
}
/// Removes the request from the storage and returns it (if present).
@ -35,9 +32,9 @@ where Id: Copy + Debug + Display + Hash + Eq + Send + Sync + 'static
pub fn remove_request(&mut self, id: &Id) -> Option<oneshot::Sender<Reply>> {
let ret = self.ongoing_calls.remove(id);
if ret.is_some() {
info!(self.logger, "Removing request {id}");
info!("Removing request {id}");
} else {
info!(self.logger, "Failed to remove non-present request {id}");
info!("Failed to remove non-present request {id}");
}
ret
}
@ -45,7 +42,7 @@ where Id: Copy + Debug + Display + Hash + Eq + Send + Sync + 'static
/// Inserts a new request with given id and completer (i.e. the channel capable of accepting
/// the peer's reply and completing the request).
pub fn insert_request(&mut self, id: Id, completer: oneshot::Sender<Reply>) {
info!(self.logger, "Storing a new request {id}");
info!("Storing a new request {id}");
// There will be no previous request, since Ids are assumed to be unique.
// Still, if there was, we can just safely drop it.
self.ongoing_calls.insert(id, completer);
@ -74,7 +71,7 @@ where Id: Copy + Debug + Display + Hash + Eq + Send + Sync + 'static
/// Removes all awaiting requests. Their futures will signal cancellation.
pub fn clear(&mut self) {
info!(self.logger, "Clearing all the requests.");
info!("Clearing all the requests.");
self.ongoing_calls.clear()
}

View File

@ -99,7 +99,7 @@ where
transport: Box::new(transport),
logger: logger.clone_ref(),
sender: None,
ongoing_calls: OngoingCalls::new(logger),
ongoing_calls: OngoingCalls::new(),
processor: Box::new(processor),
}
}
@ -114,7 +114,7 @@ where
/// Feeds the reply to complete the corresponding open request.
fn process_reply(&mut self, id: Id, reply: Reply) {
info!(self.logger, "Processing reply to request {id}: {reply:?}");
info!("Processing reply to request {id}: {reply:?}");
if let Err(error) = self.ongoing_calls.complete_request(id, reply) {
self.emit_error(error);
}
@ -122,7 +122,7 @@ where
/// Helper that wraps error into an appropriate event value and emits it.
fn emit_error(&mut self, error: impl Into<failure::Error> + Debug) {
info!(self.logger, "Emitting error: {error:?}");
info!("Emitting error: {error:?}");
let event = Event::Error(error.into());
self.emit_event(event);
}
@ -133,12 +133,12 @@ where
/// Main entry point for input data while running. Should be connected to the `Transport`s
/// output event stream.
pub fn process_event(&mut self, event: TransportEvent) {
debug!(self.logger, "Processing incoming transport event", || {
debug!(self.logger, "Transport event contents: {event:?}.");
debug_span!("Processing incoming transport event").in_scope(|| {
debug!("Transport event contents: {event:?}.");
match event {
TransportEvent::TextMessage(_) | TransportEvent::BinaryMessage(_) => {
let disposition = (self.processor)(event);
debug!(self.logger, "Disposition: {disposition:?}");
debug!("Disposition: {disposition:?}");
match disposition {
Disposition::HandleReply { id, reply } => self.process_reply(id, reply),
Disposition::EmitEvent { event } => self.emit_event(event),
@ -159,10 +159,10 @@ where
where
F: FnOnce(Reply) -> FallibleResult<R>,
{
debug!(self.logger, "Making a new RPC call", || {
debug_span!("Making a new RPC call").in_scope(|| {
let id = message.id();
let ret = self.ongoing_calls.open_new_request(id, f);
debug!(self.logger, "Sending message {message:?}");
debug!("Sending message {message:?}");
let sending_result = message.send(self.transport.as_mut());
if sending_result.is_err() {
// If we failed to send the request, it should be immediately removed.

View File

@ -2,6 +2,7 @@
use crate::language_server::*;
use enso_text::Utf16CodeUnit;
use strum_macros::IntoStaticStr;
@ -480,17 +481,17 @@ pub struct Position {
pub character: usize,
}
impls! { From + &From <enso_text::Location> for Position { |location|
impls! { From + &From <enso_text::Location<Utf16CodeUnit>> for Position { |location|
Position {
line: location.line.as_usize(),
character: location.column.as_usize(),
line: location.line.value,
character: location.offset.value,
}
}}
impls! { From + &From <Position> for enso_text::Location { |position|
impls! { From + &From <Position> for enso_text::Location<Utf16CodeUnit> { |position|
enso_text::Location {
line: position.line.into(),
column: position.character.into(),
offset: position.character.into(),
}
}}
@ -508,14 +509,14 @@ pub struct TextRange {
pub end: Position,
}
impls! { From + &From <enso_text::Range<enso_text::Location>> for TextRange { |range|
impls! { From + &From <enso_text::Range<enso_text::Location<Utf16CodeUnit>>> for TextRange { |range|
TextRange {
start : range.start.into(),
end : range.end.into(),
}
}}
impls! { From + &From <TextRange> for enso_text::Range<enso_text::Location> { |range|
impls! { From + &From <TextRange> for enso_text::Range<enso_text::Location<Utf16CodeUnit>> { |range|
enso_text::Range::new(range.start.into(), range.end.into())
}}
@ -542,12 +543,14 @@ impl TextEdit {
/// Example:
/// ```
/// # use engine_protocol::language_server::{TextEdit, Position, TextRange};
/// // Note that 🌊 has two UTF-16 code units.
/// let source = "\n333<->🌊12345\n";
/// let target = "\n333x🔥12345\n";
/// let expected_removed_len = "<->🌊".encode_utf16().count();
/// let diff = TextEdit::from_prefix_postfix_differences(source, target);
/// let edit_range = TextRange {
/// start: Position { line: 1, character: 3 },
/// end: Position { line: 1, character: 7 },
/// end: Position { line: 1, character: 3 + expected_removed_len },
/// };
/// assert_eq!(diff, TextEdit { range: edit_range, text: "x🔥".to_string() });
///
@ -570,25 +573,31 @@ impl TextEdit {
/// assert_eq!(diff, TextEdit { range: edit_range, text: "".to_string() });
/// ```
pub fn from_prefix_postfix_differences(
source: impl Into<enso_text::Text>,
target: impl Into<enso_text::Text>,
source: impl Into<enso_text::Rope>,
target: impl Into<enso_text::Rope>,
) -> TextEdit {
use enso_text::unit::*;
use enso_text::index::*;
use enso_text::Range;
let source = source.into();
let target = target.into();
let source_len = source.len().to_diff();
let target_len = target.len().to_diff();
let common_lengths = source.common_prefix_and_suffix(&target);
let source_start_byte = common_lengths.prefix;
let source_end_byte = Bytes::from(source.len()) - common_lengths.suffix;
let source_start_byte = 0.byte() + common_lengths.prefix;
let source_end_byte = 0.byte() + source_len - common_lengths.suffix;
let source_start_position = source.location_of_byte_offset_snapped(source_start_byte);
let source_end_position = source.location_of_byte_offset_snapped(source_end_byte);
let source_start_position = source.offset_to_location_snapped(source_start_byte);
let source_start_position =
source.utf16_code_unit_location_of_location(source_start_position);
let source_end_position = source.offset_to_location_snapped(source_end_byte);
let source_end_position = source.utf16_code_unit_location_of_location(source_end_position);
let source_text_range = Range::new(source_start_position, source_end_position);
let target_len: Bytes = target.len().into();
let target_range = common_lengths.prefix..(target_len - common_lengths.suffix);
let start = 0.byte() + common_lengths.prefix;
let end = 0.byte() + target_len - common_lengths.suffix;
let target_range = start..end;
let target_text = target.sub(target_range).to_string();
TextEdit { range: source_text_range.into(), text: target_text }
@ -876,14 +885,14 @@ pub struct SuggestionEntryScope {
pub end: Position,
}
impls! { From + &From <RangeInclusive<enso_text::Location>> for SuggestionEntryScope { |range|
impls! { From + &From <RangeInclusive<enso_text::Location<Utf16CodeUnit>>> for SuggestionEntryScope { |range|
SuggestionEntryScope {
start : range.start().into(),
end : range.end().into(),
}
}}
impls! { From + &From <SuggestionEntryScope> for RangeInclusive<enso_text::Location> { |this|
impls! { From + &From <SuggestionEntryScope> for RangeInclusive<enso_text::Location<Utf16CodeUnit>> { |this|
this.start.into()..=this.end.into()
}}

View File

@ -11,6 +11,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]
#![warn(trivial_casts)]

View File

@ -1,6 +1,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]

View File

@ -17,6 +17,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![deny(unconditional_recursion)]
#![warn(missing_copy_implementations)]

View File

@ -34,6 +34,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![deny(unconditional_recursion)]
#![warn(missing_copy_implementations)]

View File

@ -5,6 +5,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![deny(unconditional_recursion)]
#![warn(missing_copy_implementations)]

View File

@ -2,8 +2,7 @@
//! possible in a constant time.
use crate::prelude::*;
use enso_text::traits::*;
use enso_text::unit::*;
use enso_text::index::*;
use crate::enumerate_non_empty_lines;
use crate::known;
@ -1465,8 +1464,8 @@ pub trait TraversableAst: Sized {
}
/// Calculate the span of the descendent AST node described by given crumbs.
fn range_of_descendant_at(&self, crumbs: &[Crumb]) -> FallibleResult<text::Range<Bytes>> {
let mut position = 0.bytes();
fn range_of_descendant_at(&self, crumbs: &[Crumb]) -> FallibleResult<text::Range<Byte>> {
let mut position = 0.byte();
let mut ast = self.my_ast()?;
for crumb in crumbs {
let child = ast.get(crumb)?;
@ -2238,7 +2237,7 @@ mod tests {
assert_eq!(two.repr(), "2");
let two_span = ast.range_of_descendant_at(&crumbs_to_two).unwrap();
assert_eq!(two_span, 4.bytes()..5.bytes());
assert_eq!(two_span, 4.byte()..5.byte());
assert_eq!(&expected_code[two_span], "2");
}
}

View File

@ -4,10 +4,12 @@
//! source file: the parser gives the id of particular span to the AST node representing that span.
use crate::prelude::*;
use enso_text::unit::*;
use enso_text::index::*;
use crate::Id;
use enso_text::rope::xi_rope;
use enso_text::rope::xi_rope::rope::Utf16CodeUnitsMetric;
use serde::Deserialize;
use serde::Serialize;
use uuid::Uuid;
@ -21,20 +23,20 @@ use uuid::Uuid;
/// A mapping between text position and immutable ID.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct IdMap {
pub vec: Vec<(enso_text::Range<Bytes>, Id)>,
pub vec: Vec<(enso_text::Range<Byte>, Id)>,
}
impl IdMap {
/// Create a new instance.
pub fn new(vec: Vec<(enso_text::Range<Bytes>, Id)>) -> IdMap {
pub fn new(vec: Vec<(enso_text::Range<Byte>, Id)>) -> IdMap {
IdMap { vec }
}
/// Assigns Span to given ID.
pub fn insert(&mut self, span: impl Into<enso_text::Range<Bytes>>, id: Id) {
pub fn insert(&mut self, span: impl Into<enso_text::Range<Byte>>, id: Id) {
self.vec.push((span.into(), id));
}
/// Generate random Uuid for span.
pub fn generate(&mut self, span: impl Into<enso_text::Range<Bytes>>) {
pub fn generate(&mut self, span: impl Into<enso_text::Range<Byte>>) {
self.vec.push((span.into(), Uuid::new_v4()));
}
}
@ -85,18 +87,17 @@ impl JsonIdMap {
/// Create from the [`IdMap`] structure.
///
/// The code is needed for transforming byte offsets to codepoint offsets.
pub fn from_id_map(id_map: &IdMap, code: &str) -> Self {
let char_offsets = code.char_indices().map(|(idx, _)| idx).collect_vec();
pub fn from_id_map(id_map: &IdMap, code: &enso_text::Rope) -> Self {
// let char_offsets = code.char_indices().map(|(idx, _)| idx).collect_vec();
let mut cursor = xi_rope::Cursor::new(&code.rope, 0);
let char_offsets = iter::once(0).chain(cursor.iter::<Utf16CodeUnitsMetric>()).collect_vec();
let mapped_vec = id_map.vec.iter().map(|(range, id)| {
let byte_start = range.start.as_usize();
let byte_end = range.end.as_usize();
let start: Chars = char_offsets.binary_search(&byte_start).unwrap_both().into();
let end: Chars = char_offsets.binary_search(&byte_end).unwrap_both().into();
let byte_start = range.start.value as usize;
let byte_end = range.end.value as usize;
let start = char_offsets.binary_search(&byte_start).unwrap_both();
let end = char_offsets.binary_search(&byte_end).unwrap_both();
let size = end - start;
let span = Span {
index: Index { value: start.as_usize() },
size: Size { value: size.as_usize() },
};
let span = Span { index: Index { value: start }, size: Size { value: size } };
(span, *id)
});
Self { vec: mapped_vec.collect() }

View File

@ -7,6 +7,22 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
use crate::prelude::*;
use ast_macros::*;
use enso_shapely::*;
use enso_text::index::*;
use enso_text::traits::*;
use enso_text::unit::*;
use serde::de::Deserializer;
use serde::de::Visitor;
use serde::ser::SerializeStruct;
use serde::ser::Serializer;
use serde::Deserialize;
use serde::Serialize;
use uuid::Uuid;
// ==============
@ -71,24 +87,10 @@ pub mod constants {
}
}
use crate::prelude::*;
pub use crumbs::Crumb;
pub use crumbs::Crumbs;
pub use id_map::IdMap;
use ast_macros::*;
use enso_shapely::*;
use enso_text::traits::*;
use enso_text::unit::*;
use serde::de::Deserializer;
use serde::de::Visitor;
use serde::ser::SerializeStruct;
use serde::ser::Serializer;
use serde::Deserialize;
use serde::Serialize;
use uuid::Uuid;
/// A sequence of AST nodes, typically the "token soup".
pub type Stream<T> = Vec<T>;
@ -283,7 +285,7 @@ impl Ast {
}
/// Just wraps shape, id and len into Ast node.
fn from_ast_id_len(shape: Shape<Ast>, id: Option<Id>, char_count: Chars) -> Ast {
fn from_ast_id_len(shape: Shape<Ast>, id: Option<Id>, char_count: usize) -> Ast {
let with_length = WithLength { wrapped: shape, length: char_count };
let with_id = WithID { wrapped: with_length, id };
Ast { wrapped: Rc::new(with_id) }
@ -328,10 +330,10 @@ impl Ast {
///
/// Returned index is the position of the first character of child's text representation within
/// the text representation of this AST node.
pub fn child_offset(&self, child: &Ast) -> FallibleResult<Bytes> {
pub fn child_offset(&self, child: &Ast) -> FallibleResult<Byte> {
let searched_token = Token::Ast(child);
let mut found_child = false;
let mut position = 0.bytes();
let mut position = 0.byte();
self.shape().feed_to(&mut |token: Token| {
if searched_token == token {
found_child = true
@ -347,7 +349,7 @@ impl Ast {
}
/// Get the span (relative to self) for a child node identified by given crumb.
pub fn span_of_child_at(&self, crumb: &Crumb) -> FallibleResult<enso_text::Range<Bytes>> {
pub fn span_of_child_at(&self, crumb: &Crumb) -> FallibleResult<enso_text::Range<Byte>> {
let child = self.get(crumb)?;
let offset = self.child_offset(child)?;
Ok(enso_text::Range::new(offset, offset + child.len()))
@ -384,7 +386,7 @@ impl Serialize for Ast {
if self.id.is_some() {
state.serialize_field(ID, &self.id)?;
}
state.serialize_field(LENGTH, &self.length.as_usize())?;
state.serialize_field(LENGTH, &self.length)?;
state.end()
}
}
@ -420,7 +422,7 @@ impl<'de> Visitor<'de> for AstDeserializationVisitor {
let shape = shape.ok_or_else(|| serde::de::Error::missing_field(SHAPE))?;
let id = id.unwrap_or(None); // allow missing `id` field
let len = len.ok_or_else(|| serde::de::Error::missing_field(LENGTH))?;
Ok(Ast::from_ast_id_len(shape, id, len.into()))
Ok(Ast::from_ast_id_len(shape, id, len))
}
}
@ -1064,15 +1066,15 @@ pub trait HasIdMap {
#[derive(Debug, Clone, Default)]
struct IdMapBuilder {
id_map: IdMap,
offset: Bytes,
offset: Byte,
}
impl TokenConsumer for IdMapBuilder {
fn feed(&mut self, token: Token) {
match token {
Token::Off(val) => self.offset += Bytes::from(' '.len_utf8() * val),
Token::Chr(_) => self.offset += 1.bytes(),
Token::Str(val) => self.offset += Bytes::from(val.len()),
Token::Off(val) => self.offset += Byte::from(' '.len_utf8() * val),
Token::Chr(_) => self.offset += 1.byte(),
Token::Str(val) => self.offset += Byte::from(val.len()),
Token::Ast(val) => {
let begin = self.offset;
val.shape().feed_to(self);
@ -1106,7 +1108,7 @@ pub trait HasRepr {
/// May be implemented in a quicker way than building string. Must meet the constraint
/// `x.len() == x.repr().len()` for any `x: impl HasRepr`.
fn len(&self) -> Bytes {
self.repr().len().into()
self.repr().len().bytes()
}
/// Check if the representation is empty.
@ -1118,8 +1120,8 @@ pub trait HasRepr {
///
/// May be implemented in a quicker way than building string. Must meet the constraint
/// `x.char_count() == x.repr().chars().count()` for any `x: impl HasRepr`.
fn char_count(&self) -> Chars {
self.repr().chars().count().into()
fn char_count(&self) -> usize {
self.repr().chars().count()
}
}
@ -1147,9 +1149,9 @@ struct LengthBuilder {
impl TokenConsumer for LengthBuilder {
fn feed(&mut self, token: Token) {
match token {
Token::Off(val) => self.length += Bytes::from(' '.len_utf8() * val),
Token::Chr(chr) => self.length += Bytes::from(chr.len_utf8()),
Token::Str(val) => self.length += Bytes::from(val.len()),
Token::Off(val) => self.length += (' '.len_utf8() * val).bytes(),
Token::Chr(chr) => self.length += chr.len_utf8().bytes(),
Token::Str(val) => self.length += val.len().bytes(),
Token::Ast(val) => val.shape().feed_to(self),
}
}
@ -1157,16 +1159,16 @@ impl TokenConsumer for LengthBuilder {
#[derive(Debug, Clone, Copy, Default)]
struct CharCountBuilder {
char_count: Chars,
char_count: usize,
}
impl TokenConsumer for CharCountBuilder {
fn feed(&mut self, token: Token) {
match token {
Token::Off(val) => self.char_count += Chars::from(val),
Token::Chr(_) => self.char_count += 1.chars(),
Token::Str(val) => self.char_count += Chars::from(val.chars().count()),
Token::Off(val) => self.char_count += val,
Token::Chr(_) => self.char_count += 1,
Token::Str(val) => self.char_count += val.chars().count(),
Token::Ast(val) => val.shape().feed_to(self),
}
}
@ -1185,7 +1187,7 @@ impl<T: HasTokens> HasRepr for T {
consumer.length
}
fn char_count(&self) -> Chars {
fn char_count(&self) -> usize {
let mut consumer = CharCountBuilder::default();
self.feed_to(&mut consumer);
consumer.char_count
@ -1235,7 +1237,7 @@ where T: HasRepr
self.deref().len()
}
fn char_count(&self) -> Chars {
fn char_count(&self) -> usize {
self.deref().char_count()
}
}
@ -1244,19 +1246,19 @@ where T: HasRepr
#[derive(Debug, Clone)]
struct TraverserWithOffset<F> {
offset: Chars,
offset: usize,
callback: F,
}
impl<F> TraverserWithOffset<F> {
pub fn new(callback: F) -> TraverserWithOffset<F> {
let offset = 0.chars();
let offset = 0;
TraverserWithOffset { offset, callback }
}
}
impl<F> TokenConsumer for TraverserWithOffset<F>
where F: FnMut(Chars, &Ast)
where F: FnMut(usize, &Ast)
{
fn feed(&mut self, token: Token) {
if let Token::Ast(val) = token {
@ -1269,13 +1271,13 @@ where F: FnMut(Chars, &Ast)
}
/// Visits each Ast node, while keeping track of its index.
pub fn traverse_with_offset(ast: &impl HasTokens, f: impl FnMut(Chars, &Ast)) {
pub fn traverse_with_offset(ast: &impl HasTokens, f: impl FnMut(usize, &Ast)) {
let mut traverser = TraverserWithOffset::new(f);
ast.feed_to(&mut traverser);
}
/// Visits each Ast node, while keeping track of its span.
pub fn traverse_with_span(ast: &impl HasTokens, mut f: impl FnMut(enso_text::Range<Chars>, &Ast)) {
pub fn traverse_with_span(ast: &impl HasTokens, mut f: impl FnMut(enso_text::Range<usize>, &Ast)) {
traverse_with_offset(ast, move |offset, ast| {
f(enso_text::Range::new(offset, offset + ast.char_count()), ast)
})
@ -1293,7 +1295,7 @@ pub struct WithLength<T> {
#[shrinkwrap(main_field)]
#[serde(flatten)]
pub wrapped: T,
pub length: Chars,
pub length: usize,
}
impl<T> HasRepr for WithLength<T>
@ -1307,7 +1309,7 @@ where T: HasRepr
self.deref().len()
}
fn char_count(&self) -> Chars {
fn char_count(&self) -> usize {
self.length
}
}
@ -1761,7 +1763,7 @@ mod tests {
fn ast_length() {
let ast = Ast::prefix(Ast::var(""), Ast::var("YY"));
assert_eq!(ast.len(), 6.bytes());
assert_eq!(ast.char_count(), 5.chars());
assert_eq!(ast.char_count(), 5);
}
#[test]
@ -1773,7 +1775,7 @@ mod tests {
#[test]
fn ast_id_map() {
let span = |ix: usize, length: usize| {
enso_text::Range::<Bytes>::new(ix.into(), (ix + length).into())
enso_text::Range::<Byte>::new(ix.into(), (ix + length).into())
};
let uid = default();
let ids = vec![(span(0, 2), uid), (span(3, 2), uid), (span(0, 5), uid)];
@ -1790,7 +1792,7 @@ mod tests {
let v = Var { name: ident.clone() };
let ast = Ast::from(v);
assert!(ast.wrapped.id.is_some());
assert_eq!(ast.wrapped.wrapped.length, ident.chars().count().into());
assert_eq!(ast.wrapped.wrapped.length, ident.chars().count());
}
#[test]
@ -1822,7 +1824,7 @@ mod tests {
let expected_uuid = Id::parse_str(uuid_str).ok();
assert_eq!(ast.id, expected_uuid);
let expected_length = 3.chars();
let expected_length = 3;
assert_eq!(ast.length, expected_length);
let expected_var = Var { name: var_name.into() };
@ -1897,15 +1899,15 @@ mod tests {
#[test]
fn utf8_lengths() {
let var = Ast::var("");
assert_eq!(var.char_count(), 1.chars());
assert_eq!(var.char_count(), 1);
assert_eq!(var.len(), 3.bytes());
let idmap = var.id_map();
assert_eq!(idmap.vec[0].0, enso_text::Range::new(0.bytes(), 3.bytes()));
assert_eq!(idmap.vec[0].0, enso_text::Range::new(0.byte(), 3.byte()));
assert_eq!(idmap.vec[0].1, var.id.unwrap());
let builder_with_char = Token::Chr('壱');
assert_eq!(builder_with_char.char_count(), 1.chars());
assert_eq!(builder_with_char.char_count(), 1);
assert_eq!(builder_with_char.len(), 3.bytes());
}
}

View File

@ -3,6 +3,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]

View File

@ -1,6 +1,7 @@
//! A module containing structures and traits used in parser API.
use crate::prelude::*;
use enso_text::index::*;
use enso_text::traits::*;
use enso_text::unit::*;
@ -43,11 +44,11 @@ pub struct SourceFile {
/// The whole content of file.
pub content: String,
/// The range in bytes of module's "Code" section.
pub code: Range<Bytes>,
pub code: Range<Byte>,
/// The range in bytes of module's "Id Map" section.
pub id_map: Range<Bytes>,
pub id_map: Range<Byte>,
/// The range in bytes of module's "Metadata" section.
pub metadata: Range<Bytes>,
pub metadata: Range<Byte>,
}
impl Display for SourceFile {
@ -64,24 +65,24 @@ impl SourceFile {
/// the whole contents is treated as the code.
pub fn new(content: String) -> Self {
pub const METADATA_LINES: usize = 3;
let nl_offsets = content.char_indices().filter_map(|(ix, c)| (c == '\n').as_some(ix));
let nl_offsets_bytes = nl_offsets.map(Bytes::from);
let nl_offsets_from_end = nl_offsets_bytes.rev().take(METADATA_LINES).collect_vec();
match nl_offsets_from_end.as_slice() {
[last, before_last, two_before_last] => {
let nl_indices = content.char_indices().filter_map(|(ix, c)| (c == '\n').as_some(ix));
let nl_indices_bytes = nl_indices.map(Byte::from);
let nl_indices_from_end = nl_indices_bytes.rev().take(METADATA_LINES).collect_vec();
match nl_indices_from_end.as_slice() {
&[last, before_last, two_before_last] => {
// Last line should be metadata. Line before should be id map. Line before is the
// metadata tag.
// We check that tag matches and that trailing lines looks like JSON list/object
// respectively.
let code_length = *two_before_last + 1.bytes() - Bytes::from(NEWLINES_BEFORE_TAG);
let code_range = 0.bytes()..code_length;
let tag_range = two_before_last + 1.bytes()..*before_last;
let id_map_range = before_last + 1.bytes()..*last;
let metadata_range = last + 1.bytes()..Bytes::from(content.len());
let tag = &content[tag_range.start.as_usize()..tag_range.end.as_usize()];
let idmap = &content[id_map_range.start.as_usize()..id_map_range.end.as_usize()];
let metadata =
&content[metadata_range.start.as_usize()..metadata_range.end.as_usize()];
let code_length =
two_before_last + 1.byte_diff() - ByteDiff::from(NEWLINES_BEFORE_TAG);
let code_range = 0.byte()..(0.byte() + code_length);
let tag_range = two_before_last + 1.byte_diff()..before_last;
let id_map_range = before_last + 1.byte_diff()..last;
let metadata_range = last + 1.byte_diff()..Byte::from(content.len());
let tag = &content[tag_range.start.value..tag_range.end.value];
let idmap = &content[id_map_range.start.value..id_map_range.end.value];
let metadata = &content[metadata_range.start.value..metadata_range.end.value];
let tag_matching = tag == METADATA_TAG;
let idmap_matching = Self::looks_like_idmap(idmap);
let metadata_matching = Self::looks_like_metadata(metadata);
@ -102,9 +103,9 @@ impl SourceFile {
/// Create a description of source file consisting only of code, with no metadata.
fn new_without_metadata(content: String) -> Self {
let length = Bytes::from(content.len());
let length = Byte::from(content.len());
Self {
code: (0.bytes()..length).into(),
code: (0.byte()..length).into(),
id_map: (length..length).into(),
metadata: (length..length).into(),
content,
@ -136,9 +137,9 @@ impl SourceFile {
self.slice(&self.metadata)
}
fn slice(&self, range: &Range<Bytes>) -> &str {
let start = range.start.as_usize();
let end = range.end.as_usize();
fn slice(&self, range: &Range<Byte>) -> &str {
let start = range.start.value;
let end = range.end.value;
&self.content[start..end]
}
}
@ -188,7 +189,7 @@ fn to_json_single_line(val: &impl Serialize) -> std::result::Result<String, serd
impl<M: Metadata> ParsedSourceFile<M> {
/// Serialize to the SourceFile structure,
pub fn serialize(&self) -> std::result::Result<SourceFile, serde_json::Error> {
let code = self.ast.repr();
let code = self.ast.repr().into();
let before_tag = "\n".repeat(NEWLINES_BEFORE_TAG);
let before_idmap = "\n";
let json_id_map = JsonIdMap::from_id_map(&self.ast.id_map(), &code);
@ -196,18 +197,20 @@ impl<M: Metadata> ParsedSourceFile<M> {
let before_metadata = "\n";
let metadata = to_json_single_line(&self.metadata)?;
let id_map_start = code.len() + before_tag.len() + METADATA_TAG.len() + before_idmap.len();
let id_map_start_bytes = Bytes::from(id_map_start);
let id_map_start =
code.len().value + before_tag.len() + METADATA_TAG.len() + before_idmap.len();
let id_map_start_bytes = Byte::from(id_map_start);
let metadata_start = id_map_start + id_map.len() + before_metadata.len();
let metadata_start_bytes = Bytes::from(metadata_start);
let metadata_start_bytes = Byte::from(metadata_start);
Ok(SourceFile {
content: iformat!(
"{code}{before_tag}{METADATA_TAG}{before_idmap}{id_map}\
{before_metadata}{metadata}"
),
code: (0.bytes()..Bytes::from(code.len())).into(),
id_map: (id_map_start_bytes..id_map_start_bytes + Bytes::from(id_map.len())).into(),
metadata: (metadata_start_bytes..metadata_start_bytes + Bytes::from(metadata.len()))
code: (0.byte()..code.len().to_byte()).into(),
id_map: (id_map_start_bytes..id_map_start_bytes + ByteDiff::from(id_map.len()))
.into(),
metadata: (metadata_start_bytes..metadata_start_bytes + ByteDiff::from(metadata.len()))
.into(),
})
}
@ -262,8 +265,6 @@ where T: Fail {
mod test {
use super::*;
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
struct Metadata {
foo: usize,
@ -277,7 +278,7 @@ mod test {
let node = ast::Ast::infix_var("2", "+", "2");
let infix = ast::Ast::infix(main, "=", node);
let ast: ast::known::Module = ast::Ast::one_line_module(infix).try_into().unwrap();
let repr = ast.repr();
let repr = ast.repr().into();
let metadata = Metadata { foo: 321 };
let source = ParsedSourceFile { ast, metadata };
let serialized = source.serialize().unwrap();

View File

@ -68,7 +68,7 @@ impl Client {
/// Parses Enso code with JS-based parser.
pub fn parse(&self, program: String, ids: IdMap) -> api::Result<Ast> {
let ast = || {
let ids = JsonIdMap::from_id_map(&ids, &program);
let ids = JsonIdMap::from_id_map(&ids, &program.clone().into());
let json_ids = serde_json::to_string(&ids)?;
let json_ast = parse(program, json_ids)?;
let ast = from_json_str_without_recursion_limit(&json_ast)?;

View File

@ -9,6 +9,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]
#![warn(trivial_casts)]

View File

@ -1,6 +1,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
use enso_prelude::*;

View File

@ -1,6 +1,7 @@
//! Utilities for writing tests using parser. Should not be used in production parts.
use crate::prelude::*;
use enso_text::unit::*;
use crate::Parser;
@ -41,7 +42,7 @@ impl ParserTestExts for Parser {
let program = program.into();
DEBUG!("parsing " program);
let ast = self.parse(program.clone(), default()).unwrap();
assert_eq!(ast.shape().len().as_usize(), program.len());
assert_eq!(ast.shape().len(), program.len().bytes());
validate_spans(&ast);
assert_eq!(ast.repr(), program, "{:?}", ast);
ast

View File

@ -240,7 +240,7 @@ impl Client {
/// Sends a request to parser service to parse Enso code.
pub fn parse(&mut self, program: String, ids: IdMap) -> api::Result<Ast> {
let ids = JsonIdMap::from_id_map(&ids, &program);
let ids = JsonIdMap::from_id_map(&ids, &program.as_str().into());
let request = Request::ParseRequest { program, ids };
let response = self.rpc_call::<serde_json::Value>(request)?;
match response {

View File

@ -1,6 +1,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
use ast::crumbs::PatternMatchCrumb::*;
use ast::crumbs::*;

View File

@ -89,7 +89,7 @@ impl<T: Payload> SpanTreeGenerator<T> for String {
/// An utility to generate children with increasing offsets.
#[derive(Debug, Default)]
struct ChildGenerator<T> {
current_offset: Bytes,
current_offset: ByteDiff,
children: Vec<node::Child<T>>,
}
@ -97,7 +97,7 @@ impl<T: Payload> ChildGenerator<T> {
/// Add spacing to current generator state. It will be taken into account for the next generated
/// children's offsets
fn spacing(&mut self, size: usize) {
self.current_offset += Bytes::from(size);
self.current_offset += (size as i32).byte_diff();
}
fn generate_ast_node(
@ -226,7 +226,7 @@ fn generate_node_for_ast<T: Payload>(
.unwrap()
.generate_node(kind, context),
_ => {
let size = ast.len();
let size = (ast.len().value as i32).byte_diff();
let ast_id = ast.id;
let children = default();
let name = ast::identifier::name(ast);

View File

@ -15,6 +15,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]
#![warn(trivial_casts)]

View File

@ -1,6 +1,7 @@
//! A module with SpanTree structure definition.
use crate::prelude::*;
use enso_text::index::*;
use enso_text::unit::*;
use crate::iter::LeafIterator;
@ -36,7 +37,7 @@ pub trait Payload = Default + Clone;
#[allow(missing_docs)]
pub struct Node<T> {
pub kind: Kind,
pub size: Bytes,
pub size: ByteDiff,
pub children: Vec<Child<T>>,
pub ast_id: Option<ast::Id>,
pub payload: T,
@ -132,7 +133,7 @@ impl<T> Node<T> {
self.kind = k.into();
self
}
pub fn with_size(mut self, size: Bytes) -> Self {
pub fn with_size(mut self, size: ByteDiff) -> Self {
self.size = size;
self
}
@ -182,7 +183,7 @@ pub struct Child<T = ()> {
/// A child node.
pub node: Node<T>,
/// An offset counted from the parent node starting index to the start of this node's span.
pub offset: Bytes,
pub offset: ByteDiff,
/// AST crumbs which lead from parent to child associated AST node.
pub ast_crumbs: ast::Crumbs,
}
@ -263,7 +264,7 @@ impl<T: Payload> ChildBuilder<T> {
let builder = ChildBuilder::new(new_child);
let child = f(builder).child;
let offset_diff = child.offset - offset;
node.size += child.size + offset_diff;
node.size = node.size + child.size + offset_diff;
node.children.push(child);
}
@ -285,7 +286,7 @@ impl<T: Payload> ChildBuilder<T> {
}
/// Offset setter.
pub fn offset(mut self, offset: Bytes) -> Self {
pub fn offset(mut self, offset: ByteDiff) -> Self {
self.offset = offset;
self
}
@ -303,7 +304,7 @@ impl<T: Payload> ChildBuilder<T> {
}
/// Size setter.
pub fn size(mut self, size: Bytes) -> Self {
pub fn size(mut self, size: ByteDiff) -> Self {
self.node.size = size;
self
}
@ -429,7 +430,7 @@ pub struct Ref<'a, T = ()> {
/// The node's ref.
pub node: &'a Node<T>,
/// Span begin's offset counted from the root expression.
pub span_offset: Bytes,
pub span_offset: Byte,
/// Crumbs specifying this node position related to root.
pub crumbs: Crumbs,
/// Ast crumbs locating associated AST node, related to the root's AST node.
@ -455,7 +456,7 @@ impl<'a, T: Payload> Ref<'a, T> {
}
/// Get span of current node.
pub fn span(&self) -> text::Range<Bytes> {
pub fn span(&self) -> text::Range<Byte> {
let start = self.span_offset;
let end = self.span_offset + self.node.size;
(start..end).into()
@ -559,7 +560,7 @@ impl<'a, T: Payload> Ref<'a, T> {
/// Get the node which exactly matches the given Span. If there many such node's, it pick first
/// found by DFS.
pub fn find_by_span(self, span: &text::Range<Bytes>) -> Option<Ref<'a, T>> {
pub fn find_by_span(self, span: &text::Range<Byte>) -> Option<Ref<'a, T>> {
if self.span() == *span {
Some(self)
} else {
@ -648,9 +649,9 @@ pub struct RefMut<'a, T = ()> {
/// The node's ref.
node: &'a mut Node<T>,
/// An offset counted from the parent node start to the start of this node's span.
pub offset: Bytes,
pub offset: ByteDiff,
/// Span begin's offset counted from the root expression.
pub span_offset: Bytes,
pub span_offset: Byte,
/// Crumbs specifying this node position related to root.
pub crumbs: Crumbs,
/// Ast crumbs locating associated AST node, related to the root's AST node.
@ -678,7 +679,7 @@ impl<'a, T: Payload> RefMut<'a, T> {
}
/// Get span of current node.
pub fn span(&self) -> text::Range<Bytes> {
pub fn span(&self) -> text::Range<Byte> {
text::Range::new(self.span_offset, self.span_offset + self.size)
}
@ -686,7 +687,7 @@ impl<'a, T: Payload> RefMut<'a, T> {
fn child_from_ref(
index: usize,
child: &'a mut Child<T>,
mut span_begin: Bytes,
mut span_begin: Byte,
crumbs: Crumbs,
mut ast_crumbs: ast::Crumbs,
) -> RefMut<'a, T> {
@ -850,7 +851,7 @@ mod test {
use crate::SpanTree;
use ast::crumbs;
use enso_text::unit::*;
use enso_text::index::*;
#[test]
fn node_lookup() {
@ -873,11 +874,11 @@ mod test {
let grand_child2 = child2.clone().get_descendant(&vec![1]).unwrap();
// Span begin.
assert_eq!(root.span_offset, 0.bytes());
assert_eq!(child1.span_offset, 0.bytes());
assert_eq!(child2.span_offset, 2.bytes());
assert_eq!(grand_child1.span_offset, 2.bytes());
assert_eq!(grand_child2.span_offset, 5.bytes());
assert_eq!(root.span_offset, 0.byte());
assert_eq!(child1.span_offset, 0.byte());
assert_eq!(child2.span_offset, 2.byte());
assert_eq!(grand_child1.span_offset, 2.byte());
assert_eq!(grand_child2.span_offset, 5.byte());
// Length
assert_eq!(root.node.size.value, 7);

View File

@ -766,7 +766,7 @@ impl Handle {
let ast_so_far = self.module.ast();
let definition = self.definition()?;
let new_definition = f(definition.item)?;
info!(self.logger, "Applying graph changes onto definition");
info!("Applying graph changes onto definition");
let new_ast = new_definition.ast.into();
let new_module = ast_so_far.set_traversing(&definition.crumbs, new_ast)?;
self.module.update_ast(new_module)
@ -795,7 +795,7 @@ impl Handle {
/// Adds a new node to the graph and returns information about created node.
pub fn add_node(&self, node: NewNodeInfo) -> FallibleResult<ast::Id> {
info!(self.logger, "Adding node with expression `{node.expression}`");
info!("Adding node with expression `{}`", node.expression);
let expression_ast = self.parse_node_expression(&node.expression)?;
let main_line = MainLine::from_ast(&expression_ast).ok_or(FailedToCreateNode)?;
let documentation = node
@ -827,7 +827,7 @@ impl Handle {
/// Removes the node with given Id.
pub fn remove_node(&self, id: ast::Id) -> FallibleResult {
info!(self.logger, "Removing node {id}");
info!("Removing node {id}");
self.update_definition_ast(|definition| {
let mut graph = GraphInfo::from_definition(definition);
graph.remove_node(id)?;
@ -842,7 +842,7 @@ impl Handle {
/// Sets the given's node expression.
#[profile(Debug)]
pub fn set_expression(&self, id: ast::Id, expression_text: impl Str) -> FallibleResult {
info!(self.logger, "Setting node {id} expression to `{expression_text.as_ref()}`");
info!("Setting node {id} expression to `{}`", expression_text.as_ref());
let new_expression_ast = self.parse_node_expression(expression_text)?;
self.set_expression_ast(id, new_expression_ast)
}
@ -850,7 +850,7 @@ impl Handle {
/// Sets the given's node expression.
#[profile(Debug)]
pub fn set_expression_ast(&self, id: ast::Id, expression: Ast) -> FallibleResult {
info!(self.logger, "Setting node {id} expression to `{expression.repr()}`");
info!("Setting node {id} expression to `{}`", expression.repr());
self.update_definition_ast(|definition| {
let mut graph = GraphInfo::from_definition(definition);
graph.edit_node(id, expression)?;
@ -888,7 +888,7 @@ impl Handle {
use double_representation::refactorings::collapse::collapse;
use double_representation::refactorings::collapse::Collapsed;
let nodes = nodes.into_iter().map(|id| self.node(id)).collect::<Result<Vec<_>, _>>()?;
info!(self.logger, "Collapsing {nodes:?}.");
info!("Collapsing {nodes:?}.");
let collapsed_positions = nodes
.iter()
.filter_map(|node| node.metadata.as_ref().and_then(|metadata| metadata.position));
@ -921,7 +921,7 @@ impl Handle {
let mut graph = GraphInfo::from_definition(definition);
graph.update_node(id, |node| {
let new_node = f(node);
info!(self.logger, "Setting node {id} line to `{new_node.repr()}`");
info!("Setting node {id} line to `{}`", new_node.repr());
Some(new_node)
})?;
Ok(graph.source)
@ -992,7 +992,7 @@ pub mod tests {
use double_representation::identifier::NormalizedName;
use double_representation::project;
use engine_protocol::language_server::MethodPointer;
use enso_text::traits::*;
use enso_text::index::*;
use parser::Parser;
use wasm_bindgen_test::wasm_bindgen_test;
@ -1066,7 +1066,7 @@ pub mod tests {
pub fn suggestion_db(&self) -> Rc<model::SuggestionDatabase> {
use model::suggestion_database::SuggestionDatabase;
let entries = self.suggestions.iter();
Rc::new(SuggestionDatabase::new_from_entries(Logger::new("Test"), entries))
Rc::new(SuggestionDatabase::new_from_entries(entries))
}
}
@ -1115,7 +1115,7 @@ pub mod tests {
fn graph_controller_notification_relay() {
Fixture::set_up().run(|graph| async move {
let mut sub = graph.subscribe();
let change = TextChange { range: (12.bytes()..12.bytes()).into(), text: "2".into() };
let change = TextChange { range: (12.byte()..12.byte()).into(), text: "2".into() };
graph.module.apply_code_change(change, &graph.parser, default()).unwrap();
assert_eq!(Some(Notification::Invalidate), sub.next().await);
});

View File

@ -224,14 +224,14 @@ impl Handle {
///
/// Fails if method graph cannot be created (see `graph_for_method` documentation).
pub async fn enter_method_pointer(&self, local_call: &LocalCall) -> FallibleResult {
debug!(self.logger, "Entering node {local_call.call}.");
debug!("Entering node {}.", local_call.call);
let method_ptr = &local_call.definition;
let graph = controller::Graph::new_method(&self.logger, &self.project, method_ptr);
let graph = graph.await?;
self.execution_ctx.push(local_call.clone()).await?;
debug!(self.logger, "Replacing graph with {graph:?}.");
debug!("Replacing graph with {graph:?}.");
self.graph.replace(graph);
debug!(self.logger, "Sending graph invalidation signal.");
debug!("Sending graph invalidation signal.");
self.notifier.publish(Notification::EnteredNode(local_call.clone())).await;
Ok(())

View File

@ -90,7 +90,6 @@ impl Handle {
let my_code = self.code();
if code != my_code {
error!(
self.logger,
"The module controller ast was not synchronized with text editor \
content!\n >>> Module: {my_code}\n >>> Editor: {code}"
);
@ -186,7 +185,7 @@ impl Handle {
let logger = Logger::new("Mocked Module Controller");
let ast = parser.parse(code.to_string(), id_map)?.try_into()?;
let metadata = default();
let model = Rc::new(model::module::Plain::new(&logger, path, ast, metadata, repository));
let model = Rc::new(model::module::Plain::new(path, ast, metadata, repository));
Ok(Handle { model, language_server, parser, logger })
}
@ -212,7 +211,7 @@ mod test {
use ast;
use ast::Ast;
use ast::BlockLine;
use enso_text::traits::*;
use enso_text::index::*;
use parser::Parser;
use uuid::Uuid;
use wasm_bindgen_test::wasm_bindgen_test;
@ -229,16 +228,16 @@ mod test {
let uuid3 = Uuid::new_v4();
let uuid4 = Uuid::new_v4();
let id_map = ast::IdMap::new(vec![
((0.bytes()..1.bytes()).into(), uuid1),
((1.bytes()..2.bytes()).into(), uuid2),
((2.bytes()..3.bytes()).into(), uuid3),
((0.bytes()..3.bytes()).into(), uuid4),
((0.byte()..1.byte()).into(), uuid1),
((1.byte()..2.byte()).into(), uuid2),
((2.byte()..3.byte()).into(), uuid3),
((0.byte()..3.byte()).into(), uuid4),
]);
let controller =
Handle::new_mock(location, code, id_map, ls, parser, default()).unwrap();
// Change code from "2+2" to "22+2"
let change = enso_text::Change::inserted(0.bytes(), "2".to_string());
let change = enso_text::Change::inserted(0.byte(), "2".to_string());
controller.apply_code_change(change).unwrap();
let expected_ast = Ast::new_no_id(ast::Module {
lines: vec![BlockLine {

View File

@ -22,7 +22,9 @@ use double_representation::node::NodeInfo;
use double_representation::project;
use double_representation::tp;
use engine_protocol::language_server;
use enso_text::Byte;
use enso_text::Location;
use enso_text::Rope;
use flo_stream::Subscriber;
use parser::Parser;
@ -505,7 +507,7 @@ pub struct Searcher {
language_server: Rc<language_server::Connection>,
ide: controller::Ide,
this_arg: Rc<Option<ThisNode>>,
position_in_code: Immutable<Location>,
position_in_code: Immutable<Location<Byte>>,
project: model::Project,
/// A component list builder with favorites prepopulated with
/// [`controller::ExecutedGraph::component_groups`]. Stored to reduce the number of
@ -558,8 +560,8 @@ impl Searcher {
let module_ast = graph.graph().module.ast();
let def_id = graph.graph().id;
let def_span = double_representation::module::definition_span(&module_ast, &def_id)?;
let module_repr: enso_text::Text = module_ast.repr().into();
let position = module_repr.location_of_byte_offset_snapped(def_span.end);
let module_repr: Rope = module_ast.repr().into();
let position = module_repr.offset_to_location_snapped(def_span.end);
let this_arg = Rc::new(match mode {
Mode::NewNode { source_node: Some(node), .. } => ThisNode::new(node, &graph.graph()),
_ => None,
@ -689,13 +691,13 @@ impl Searcher {
self.invalidate_fragments_added_by_picking();
let expression_changed = old_expr != new_expr;
if expression_changed {
debug!(self.logger, "Reloading list.");
debug!("Reloading list.");
self.reload_list();
} else {
let data = self.data.borrow();
data.components.update_filtering(&data.input.pattern);
if let Actions::Loaded { list } = &data.actions {
debug!(self.logger, "Update filtering.");
debug!("Update filtering.");
list.update_filtering(&data.input.pattern);
executor::global::spawn(self.notifier.publish(Notification::NewActionList));
}
@ -847,7 +849,6 @@ impl Searcher {
match self.ide.manage_projects() {
Ok(_) => {
let ide = self.ide.clone_ref();
let logger = self.logger.clone_ref();
executor::global::spawn(async move {
// We checked that manage_projects returns Some just a moment ago, so
// unwrapping is safe.
@ -859,7 +860,7 @@ impl Searcher {
manage_projects.open_project(*id),
};
if let Err(err) = result.await {
error!(logger, "Error when creating new project: {err}");
error!("Error when creating new project: {err}");
}
});
Ok(None)
@ -1098,7 +1099,6 @@ impl Searcher {
#[profile(Debug)]
fn this_arg_type_for_next_completion(&self) -> impl Future<Output = Option<String>> {
let next_id = self.data.borrow().input.next_completion_id();
let logger = self.logger.clone_ref();
let graph = self.graph.clone_ref();
let this = self.this_arg.clone_ref();
async move {
@ -1108,7 +1108,7 @@ impl Searcher {
}
let ThisNode { id, .. } = this.deref().as_ref()?;
let opt_type = graph.expression_type(*id).await.map(Into::into);
opt_type.map_none(move || error!(logger, "Failed to obtain type for this node."))
opt_type.map_none(move || error!("Failed to obtain type for this node."))
}
}
@ -1141,7 +1141,7 @@ impl Searcher {
) {
let ls = self.language_server.clone_ref();
let graph = self.graph.graph();
let position = self.position_in_code.deref().into();
let position = self.my_utf16_location().span.into();
let this = self.clone_ref();
let return_types = return_types.into_iter().collect_vec();
let return_types_for_engine = if return_types.is_empty() {
@ -1151,9 +1151,9 @@ impl Searcher {
};
executor::global::spawn(async move {
let this_type = this_type.await;
info!(this.logger, "Requesting new suggestion list. Type of `self` is {this_type:?}.");
info!("Requesting new suggestion list. Type of `self` is {this_type:?}.");
let requests = return_types_for_engine.into_iter().map(|return_type| {
info!(this.logger, "Requesting suggestions for returnType {return_type:?}.");
info!("Requesting suggestions for returnType {return_type:?}.");
let file = graph.module.path().file_path();
ls.completion(file, &position, &this_type, &return_type, &tags)
});
@ -1161,7 +1161,7 @@ impl Searcher {
futures::future::join_all(requests).await.into_iter().collect();
match responses {
Ok(responses) => {
info!(this.logger, "Received suggestions from Language Server.");
info!("Received suggestions from Language Server.");
let list = this.make_action_list(responses.iter());
let mut data = this.data.borrow_mut();
data.actions = Actions::Loaded { list: Rc::new(list) };
@ -1171,7 +1171,7 @@ impl Searcher {
}
Err(err) => {
let msg = "Request for completions to the Language Server returned error";
error!(this.logger, "{msg}: {err}");
error!("{msg}: {err}");
let mut data = this.data.borrow_mut();
data.actions = Actions::Error(Rc::new(err.into()));
data.components =
@ -1218,7 +1218,6 @@ impl Searcher {
.map(|entry| Action::Suggestion(action::Suggestion::FromDatabase(entry)))
.handle_err(|e| {
error!(
self.logger,
"Response provided a suggestion ID that cannot be \
resolved: {e}."
)
@ -1243,6 +1242,25 @@ impl Searcher {
builder.build()
}
/// Convert a location within a current module (i.e. module being edited) to a location indexed
/// by UTF-16 code units. This enables Language Server protocol compatibility.
fn location_to_utf16(
&self,
location: Location<Byte>,
) -> suggestion_database::entry::ModuleSpan {
let module: Rope = self.graph.graph().module.ast().repr().into();
suggestion_database::entry::ModuleSpan {
module: self.module_qualified_name(),
span: module.utf16_code_unit_location_of_location(location),
}
}
/// Convert a position of the searcher in the code to an Engine-compatible UTF-16 location.
fn my_utf16_location(&self) -> suggestion_database::entry::ModuleSpan {
let location = self.position_in_code.deref().into();
self.location_to_utf16(location)
}
fn possible_function_calls(&self) -> Vec<action::Suggestion> {
let opt_result = || {
let call_ast = self.data.borrow().input.expression.as_ref()?.func.clone_ref();
@ -1253,9 +1271,8 @@ impl Searcher {
Some(entry.into_iter().map(action::Suggestion::FromDatabase).collect())
} else {
let name = &call.function_name;
let module = self.module_qualified_name();
let location = *self.position_in_code;
let entries = self.database.lookup_by_name_and_location(name, &module, location);
let location = self.my_utf16_location();
let entries = self.database.lookup_at(name, &location);
Some(entries.into_iter().map(action::Suggestion::FromDatabase).collect())
}
};
@ -1265,11 +1282,10 @@ impl Searcher {
/// For the simple function call checks if the function is called on the module (if it can be
/// easily determined) and returns the module's qualified name if it is.
fn module_whose_method_is_called(&self, call: &SimpleFunctionCall) -> Option<QualifiedName> {
let position = *self.position_in_code;
let location = self.my_utf16_location();
let this_name = ast::identifier::name(call.this_argument.as_ref()?)?;
let module_name = self.module_qualified_name();
let matching_locals =
self.database.lookup_locals_by_name_and_location(this_name, &module_name, position);
let matching_locals = self.database.lookup_locals_at(this_name, &location);
let module_name = location.module;
let not_local_name = matching_locals.is_empty();
not_local_name.and_option_from(|| {
if this_name == module_name.name().deref() {
@ -1634,12 +1650,12 @@ pub mod test {
impl MockData {
fn change_main_body(&mut self, lines: &[&str]) {
let code: enso_text::Text = dbg!(crate::test::mock::main_from_lines(lines)).into();
let location = code.location_of_text_end();
let code: Rope = crate::test::mock::main_from_lines(lines).into();
let location = code.last_line_end_location();
// TODO [mwu] Not nice that we ended up with duplicated mock data for code.
self.graph.module.code = (&code).into();
self.graph.graph.code = code.into();
self.code_location = location.into();
self.graph.graph.code = (&code).into();
self.code_location = code.utf16_code_unit_location_of_location(location).into();
}
fn expect_completion(
@ -1684,8 +1700,10 @@ pub mod test {
let mut client = language_server::MockClient::default();
client.require_all_calls();
client_setup(&mut data, &mut client);
let end_of_code = enso_text::Text::from(&data.graph.module.code).location_of_text_end();
let code_range = enso_text::Location::default()..=end_of_code;
let code = enso_text::Rope::from(&data.graph.module.code);
let start_of_code = enso_text::Location::default();
let end_of_code = code.location_of_text_end_utf16_code_unit();
let code_range = start_of_code..=end_of_code;
let scope = Scope::InModule { range: code_range };
let graph = data.graph.controller();
let node = &graph.graph().nodes().unwrap()[0];
@ -1694,7 +1712,7 @@ pub mod test {
let this = data.selected_node.and_option(this);
let logger = Logger::new("Searcher"); // new_empty
let module_name = crate::test::mock::data::module_qualified_name();
let database = suggestion_database_with_mock_entries(&logger, module_name, scope);
let database = suggestion_database_with_mock_entries(module_name, scope);
let mut ide = controller::ide::MockAPI::new();
let mut project = model::project::MockAPI::new();
let project_qname = project_qualified_name();
@ -1724,7 +1742,7 @@ pub mod test {
mode: Immutable(Mode::NewNode { node_id: searcher_target, source_node: None }),
language_server: language_server::Connection::new_mock_rc(client),
this_arg: Rc::new(this),
position_in_code: Immutable(end_of_code),
position_in_code: Immutable(code.last_line_end_location()),
project: project.clone_ref(),
list_builder_with_favorites: Rc::new(list_builder_with_favs),
node_edit_guard: node_metadata_guard,
@ -1756,11 +1774,10 @@ pub mod test {
}
fn suggestion_database_with_mock_entries(
logger: &Logger,
module_name: QualifiedName,
scope: Scope,
) -> Rc<SuggestionDatabase> {
let database = Rc::new(SuggestionDatabase::new_empty(logger));
let database = Rc::new(SuggestionDatabase::new_empty());
let entry1 = model::suggestion_database::Entry {
name: "testFunction1".to_string(),
kind: Kind::Function,

View File

@ -338,7 +338,7 @@ pub(crate) mod tests {
}
}
pub fn mock_suggestion_db(logger: impl AnyLogger) -> model::SuggestionDatabase {
pub fn mock_suggestion_db() -> model::SuggestionDatabase {
let top_module_1 = mock_module("test.Test.TopModule1");
let top_module_2 = mock_module("test.Test.TopModule2");
let sub_module_1 = mock_module("test.Test.TopModule1.SubModule1");
@ -364,7 +364,7 @@ pub(crate) mod tests {
fun6,
];
let suggestion_db = model::SuggestionDatabase::new_empty(logger);
let suggestion_db = model::SuggestionDatabase::new_empty();
for (id, entry) in all_entries.into_iter().enumerate() {
suggestion_db.put_entry(id, entry)
}
@ -404,13 +404,12 @@ pub(crate) mod tests {
#[test]
fn filtering_component_list() {
let logger = Logger::new("test::update_list_after_filtering_pattern_change");
let top_module = mock_module("test.Test.TopModule");
let sub_module = mock_module("test.Test.TopModule.SubModule");
let fun1 = mock_function(&top_module.module, "fun1");
let funx2 = mock_function(&sub_module.module, "funx1");
let all_entries = [&top_module, &sub_module, &fun1, &funx2];
let suggestion_db = model::SuggestionDatabase::new_empty(logger);
let suggestion_db = model::SuggestionDatabase::new_empty();
for (id, entry) in all_entries.into_iter().enumerate() {
suggestion_db.put_entry(id, entry.clone())
}
@ -459,8 +458,7 @@ pub(crate) mod tests {
#[test]
fn component_list_modules_tree() {
// Create a components list with sample data.
let logger = Logger::new("test::component_list_modules_tree");
let suggestion_db = mock_suggestion_db(logger);
let suggestion_db = mock_suggestion_db();
let mut builder = builder::List::new().with_local_scope_module_id(0);
builder.extend_list_and_allow_favorites_with_ids(&suggestion_db, 0..11);
let list = builder.build();

View File

@ -323,8 +323,7 @@ mod tests {
#[test]
fn building_component_list() {
let logger = Logger::new("tests::module_groups_in_component_list");
let suggestion_db = mock_suggestion_db(logger);
let suggestion_db = mock_suggestion_db();
let mut builder = List::new().with_local_scope_module_id(0);
let first_part = (0..3).chain(6..11);
let second_part = 3..6;
@ -429,8 +428,7 @@ mod tests {
/// processed as described in the docs of the [`List::build`] method.
#[test]
fn building_component_list_with_favorites() {
let logger = Logger::new("tests::building_component_list_with_favorites");
let db = mock_suggestion_db(logger);
let db = mock_suggestion_db();
let mut builder = List::new();
let qn_of_db_entry_0 = db.lookup(0).unwrap().qualified_name();
let qn_of_db_entry_1 = db.lookup(1).unwrap().qualified_name();
@ -493,8 +491,7 @@ mod tests {
/// inserted into an existing favorites group.
#[test]
fn building_component_list_with_virtual_component_in_existing_favorites_group() {
let logger = Logger::new("tests::virtual_component_in_existing_favorites_group");
let db = mock_suggestion_db(logger);
let db = mock_suggestion_db();
let mut builder = List::new();
let qn_of_db_entry_0 = db.lookup(0).unwrap().qualified_name();
let project = project::QualifiedName::standard_base_library();
@ -521,8 +518,7 @@ mod tests {
/// inserted into a new favorites group.
#[test]
fn building_component_list_with_virtual_component_in_new_favorites_group() {
let logger = Logger::new("tests::virtual_component_in_new_favorites_group");
let db = mock_suggestion_db(logger);
let db = mock_suggestion_db();
let mut builder = List::new();
let qn_of_db_entry_0 = db.lookup(0).unwrap().qualified_name();
let project = project::QualifiedName::standard_base_library();

View File

@ -333,8 +333,7 @@ mod tests {
/// components in the suggestion database.
#[test]
fn lookup_component_groups_in_suggestion_database() {
let logger = Logger::new("tests::lookup_component_groups_in_suggestion_database");
let suggestion_db = Rc::new(mock_suggestion_db(logger));
let suggestion_db = Rc::new(mock_suggestion_db());
// Prepare a mock group containing fully qualified component names in non-alphabetical
// order. Some of the names correspond to entries present in the suggestion database,
@ -377,8 +376,7 @@ mod tests {
// only names not found in the suggestion database.
#[test]
fn constructing_component_group_from_names_not_found_in_db() {
let logger = Logger::new("tests::constructing_component_group_from_names_not_found_in_db");
let suggestion_db = Rc::new(mock_suggestion_db(logger));
let suggestion_db = Rc::new(mock_suggestion_db());
let ec_group = execution_context::ComponentGroup {
project: project::QualifiedName::standard_base_library(),
name: "Input".into(),

View File

@ -176,7 +176,7 @@ mod test {
use crate::executor::test_utils::TestWithLocalPoolExecutor;
use enso_text::traits::*;
use enso_text::index::*;
use parser::Parser;
use wasm_bindgen_test::wasm_bindgen_test;
@ -206,7 +206,7 @@ mod test {
};
let mut sub = controller.subscribe();
let change = enso_text::Change::inserted(8.bytes(), "2".to_string());
let change = enso_text::Change::inserted(8.byte(), "2".to_string());
module.apply_code_change(change).unwrap();
assert_eq!(Some(Notification::Invalidate), sub.next().await);
})

View File

@ -76,7 +76,6 @@ pub struct FileToUpload<DataProvider> {
/// API.
#[derive(Clone, Debug)]
pub struct FileUploadProcess<DataProvider> {
logger: Logger,
bin_connection: Rc<binary::Connection>,
json_connection: Rc<language_server::Connection>,
file: FileToUpload<DataProvider>,
@ -97,24 +96,14 @@ pub enum UploadingState {
impl<DP: DataProvider> FileUploadProcess<DP> {
/// Constructor.
pub fn new(
parent: impl AnyLogger,
file: FileToUpload<DP>,
bin_connection: Rc<binary::Connection>,
json_connection: Rc<language_server::Connection>,
remote_path: Path,
) -> Self {
let logger = Logger::new_sub(parent, "FileUploadProcess");
let bytes_uploaded = 0;
let checksum = sha3::Sha3_224::new();
Self {
logger,
bin_connection,
json_connection,
file,
remote_path,
bytes_uploaded,
checksum,
}
Self { bin_connection, json_connection, file, remote_path, bytes_uploaded, checksum }
}
/// Upload next chunk. Returns information if all data has been uploaded.
@ -128,9 +117,11 @@ impl<DP: DataProvider> FileUploadProcess<DP> {
match self.file.data.next_chunk().await {
Ok(Some(data)) => {
debug!(
self.logger,
"Received chunk of {self.file.name} of size {data.len()} \
uploading to {self.remote_path:?}: {data:?}"
"Received chunk of {} of size {} uploading to {:?}: {:?}",
self.file.name,
data.len(),
self.remote_path,
data
);
let offset = self.bytes_uploaded;
self.bin_connection.write_bytes(&self.remote_path, offset, false, &data).await?;
@ -145,10 +136,9 @@ impl<DP: DataProvider> FileUploadProcess<DP> {
}
if self.bytes_uploaded != self.file.size {
error!(
self.logger,
"The promised file size ({self.file.size}) and uploaded \
data length ({self.bytes_uploaded}) do not match. Leaving as much data as \
received."
"The promised file size ({}) and uploaded data length ({}) do not match. \
Leaving as much data as received.",
self.file.size, self.bytes_uploaded
);
self.bytes_uploaded = self.file.size;
}
@ -207,7 +197,7 @@ impl NodeFromDroppedFileHandler {
let this = self.clone_ref();
executor::global::spawn(async move {
if let Err(err) = this.upload_file(node, file).await {
error!(this.logger, "Error while uploading file: {err}");
error!("Error while uploading file: {err}");
this.update_metadata(node, |md| md.error = Some(err.to_string()));
}
});
@ -252,13 +242,8 @@ impl NodeFromDroppedFileHandler {
let remote_path = self.data_path().append_im(&remote_name);
let bin_connection = self.project.binary_rpc();
let json_connection = self.project.json_rpc();
let mut process = FileUploadProcess::new(
&self.logger,
file,
bin_connection,
json_connection,
remote_path,
);
let mut process =
FileUploadProcess::new(file, bin_connection, json_connection, remote_path);
while process.upload_chunk().await? == UploadingState::NotFinished {
self.update_metadata(node, |md| md.bytes_uploaded = process.bytes_uploaded);
@ -508,7 +493,7 @@ mod test {
}
impl UploadingFixture {
fn new(logger: impl AnyLogger, data: TestData) -> Self {
fn new(data: TestData) -> Self {
let mut binary_cli = binary::MockClient::new();
let json_cli = language_server::MockClient::default();
json_cli.require_all_calls();
@ -520,7 +505,7 @@ mod test {
Self {
test: TestWithLocalPoolExecutor::set_up(),
chunks: data.chunks.into_iter(),
process: FileUploadProcess::new(logger, file, bin_con, json_con, data.path),
process: FileUploadProcess::new(file, bin_con, json_con, data.path),
provider_sink: Some(provider_sink),
}
}
@ -546,9 +531,8 @@ mod test {
#[test]
fn uploading_file() {
let logger = Logger::new("test::uploading_file");
let data = TestData::new(vec![vec![1, 2, 3, 4, 5], vec![3, 4, 5, 6, 7, 8]]);
let mut test = UploadingFixture::new(logger, data);
let mut test = UploadingFixture::new(data);
assert_eq!(test.next_chunk_result().unwrap(), UploadingState::NotFinished);
assert_eq!(test.next_chunk_result().unwrap(), UploadingState::NotFinished);
@ -557,10 +541,9 @@ mod test {
#[test]
fn checksum_mismatch_should_cause_an_error() {
let logger = Logger::new("test::uploading_file");
let mut data = TestData::new(vec![vec![1, 2, 3, 4, 5]]);
data.checksum = Sha3_224::new(&[3, 4, 5, 6, 7, 8]);
let mut test = UploadingFixture::new(logger, data);
let mut test = UploadingFixture::new(data);
assert_eq!(test.next_chunk_result().unwrap(), UploadingState::NotFinished);
assert!(test.next_chunk_result().is_err());

View File

@ -29,20 +29,14 @@ use futures::task::LocalSpawnExt;
/// Global spawner container. This structure is kept in the global variable `SPAWNER`. See module
/// docs for details.
#[derive(Default)]
struct GlobalSpawner {
logger: Logger,
spawner: RefCell<Option<Box<dyn LocalSpawn>>>,
}
impl Default for GlobalSpawner {
fn default() -> Self {
Self { logger: Logger::new("GlobalSpawner"), spawner: default() }
}
}
impl GlobalSpawner {
fn set_spawner(&self, spawner_to_set: impl LocalSpawn + 'static) {
info!(self.logger, "Setting new spawner");
info!("Setting new spawner");
*self.spawner.borrow_mut() = Some(Box::new(spawner_to_set))
}
@ -51,13 +45,10 @@ impl GlobalSpawner {
let mut borrowed = self.spawner.borrow_mut();
if let Some(unwrapped) = borrowed.as_mut() {
if unwrapped.spawn_local(f).is_err() {
error!(
self.logger,
"Failed to spawn the task. Global executor might have been dropped."
);
error!("Failed to spawn the task. Global executor might have been dropped.");
}
} else {
error!(self.logger, "Fail to spawn the task. No global executor has been provided.")
error!("Fail to spawn the task. No global executor has been provided.")
}
}
}

View File

@ -21,7 +21,7 @@ pub mod test;
/// An alias for a main animation loop.
pub type MainLoop = animation::Loop<Box<dyn FnMut(animation::TimeInfo)>>;
pub type MainLoop = animation::Loop;
/// Executor. Uses a single-threaded `LocalPool` underneath, relying on ensogl's
/// `animation::DynamicLoop` to do as much progress as possible on every animation frame.

View File

@ -59,7 +59,7 @@ impl Initializer {
/// Initialize all Ide objects and structures (executor, views, controllers, integration etc.)
#[profile(Task)]
pub async fn start(self) -> Result<Ide, FailedIde> {
info!(self.logger, "Starting IDE with the following config: {self.config:?}");
info!("Starting IDE with the following config: {:?}", self.config);
ensogl_text_msdf::initialized().await;
let ensogl_app = ensogl::application::Application::new(self.config.dom_parent_id());
@ -83,12 +83,12 @@ impl Initializer {
match self.initialize_ide_controller().await {
Ok(controller) => {
let ide = Ide::new(ensogl_app, view.clone_ref(), controller);
info!(self.logger, "Setup done.");
info!("Setup done.");
Ok(ide)
}
Err(error) => {
let message = format!("Failed to initialize application: {error}");
error!(self.logger, "{message}");
error!("{message}");
status_bar.add_event(ide_view::status_bar::event::Label::new(message));
Err(FailedIde { view })
}
@ -186,7 +186,7 @@ impl WithProjectManager {
/// Creates a new project and returns its id, so the newly connected project can be opened.
pub async fn create_project(&self) -> FallibleResult<Uuid> {
use project_manager::MissingComponentAction::Install;
info!(self.logger, "Creating a new project named '{self.project_name}'.");
info!("Creating a new project named '{}'.", self.project_name);
let version = enso_config::ARGS.preferred_engine_version.as_ref().map(ToString::to_string);
let name = &self.project_name;
let response = self.project_manager.create_project(name, &None, &version, &Install);
@ -209,7 +209,7 @@ impl WithProjectManager {
if let Ok(project_id) = project {
Ok(project_id)
} else {
info!(self.logger, "Attempting to create {self.project_name}");
info!("Attempting to create {}", self.project_name);
self.create_project().await
}
}
@ -243,7 +243,7 @@ pub fn register_views(app: &Application) {
app.views.register::<ide_view::component_browser::breadcrumbs::Breadcrumbs>();
app.views.register::<ide_view::component_browser::component_group::View>();
app.views.register::<ide_view::component_browser::component_group::wide::View>();
app.views.register::<ensogl_component::text::Area>();
app.views.register::<ensogl_component::text::Text>();
app.views.register::<ensogl_component::selector::NumberPicker>();
app.views.register::<ensogl_component::selector::NumberRangePicker>();

View File

@ -48,6 +48,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]
#![warn(trivial_casts)]

View File

@ -49,7 +49,6 @@ pub struct InvalidVisualizationId(VisualizationId);
/// controllers.
#[derive(Debug)]
pub struct ExecutionContext {
logger: Logger,
/// A name of definition which is a root call of this context.
pub entry_point: MethodPointer,
/// Local call stack.
@ -66,15 +65,13 @@ pub struct ExecutionContext {
impl ExecutionContext {
/// Create new execution context
pub fn new(logger: impl Into<Logger>, entry_point: MethodPointer) -> Self {
let logger = logger.into();
pub fn new(entry_point: MethodPointer) -> Self {
let stack = default();
let visualizations = default();
let computed_value_info_registry = default();
let is_ready = default();
let component_groups = default();
Self {
logger,
entry_point,
stack,
visualizations,
@ -122,7 +119,7 @@ impl ExecutionContext {
let id = visualization.id;
let (update_sender, receiver) = futures::channel::mpsc::unbounded();
let visualization = AttachedVisualization { visualization, update_sender };
info!(self.logger, "Inserting to the registry: {id}.");
info!("Inserting to the registry: {id}.");
self.visualizations.borrow_mut().insert(id, visualization);
receiver
}
@ -154,7 +151,7 @@ impl ExecutionContext {
/// This function shadows the asynchronous version from API trait.
pub fn detach_visualization(&self, id: VisualizationId) -> FallibleResult<Visualization> {
let err = || InvalidVisualizationId(id);
info!(self.logger, "Removing from the registry: {id}.");
info!("Removing from the registry: {id}.");
let removed = self.visualizations.borrow_mut().remove(&id).ok_or_else(err)?;
Ok(removed.visualization)
}
@ -243,11 +240,10 @@ impl model::execution_context::API for ExecutionContext {
// TODO [mwu] Should we consider detaching the visualization if the view has dropped the
// channel's receiver? Or we need to provide a way to re-establish the channel.
let _ = visualization.update_sender.unbounded_send(data);
debug!(self.logger, "Sending update data to the visualization {visualization_id}.");
debug!("Sending update data to the visualization {visualization_id}.");
Ok(())
} else {
error!(
self.logger,
"Failed to dispatch update to visualization {visualization_id}. \
Failed to found such visualization."
);
@ -321,8 +317,7 @@ pub mod test {
}
pub fn create(&self) -> ExecutionContext {
let logger = Logger::new("Mocked Execution Context");
let mut ec = ExecutionContext::new(logger, self.main_method_pointer());
let mut ec = ExecutionContext::new(self.main_method_pointer());
ec.component_groups = self.component_groups();
ec
}

View File

@ -68,16 +68,15 @@ impl ExecutionContext {
language_server: Rc<language_server::Connection>,
root_definition: language_server::MethodPointer,
) -> impl Future<Output = FallibleResult<Self>> {
let logger = Logger::new_sub(&parent, "ExecutionContext");
async move {
info!(logger, "Creating.");
info!("Creating.");
let id = language_server.client.create_execution_context().await?.context_id;
let logger = Logger::new_sub(&parent, iformat! {"ExecutionContext {id}"});
let model = model::execution_context::Plain::new(&logger, root_definition);
info!(logger, "Created. Id: {id}.");
let model = model::execution_context::Plain::new(root_definition);
info!("Created. Id: {id}.");
let this = Self { id, model, language_server, logger };
this.push_root_frame().await?;
info!(this.logger, "Pushed root frame.");
info!("Pushed root frame.");
Ok(this)
}
}
@ -104,7 +103,7 @@ impl ExecutionContext {
"Failed to parse a component group returned by the Engine. The group will not \
appear in the Favorites section of the Component Browser. Error: {err}"
);
error!(self.logger, "{msg}");
error!("{msg}");
};
match self.language_server.get_component_groups(&self.id).await {
Ok(ls_response) => {
@ -114,14 +113,14 @@ impl ExecutionContext {
.filter_map(|group| group.try_into().inspect_err(log_group_parsing_error).ok())
.collect();
*self.model.component_groups.borrow_mut() = Rc::new(groups);
info!(self.logger, "Loaded component groups.");
info!("Loaded component groups.");
}
Err(err) => {
let msg = iformat!(
"Failed to load component groups. No groups will appear in the Favorites \
section of the Component Browser. Error: {err}"
);
error!(self.logger, "{msg}");
error!("{msg}");
}
}
}
@ -139,7 +138,7 @@ impl ExecutionContext {
let ast_id = vis.expression_id;
let ls = self.language_server.clone_ref();
let logger = self.logger.clone_ref();
info!(logger, "About to detach visualization by id: {vis_id}.");
info!("About to detach visualization by id: {vis_id}.");
ls.detach_visualisation(&exe_id, &vis_id, &ast_id).await?;
if let Err(err) = self.model.detach_visualization(vis_id) {
warning!(logger, "Failed to update model after detaching visualization: {err:?}.")
@ -152,7 +151,7 @@ impl ExecutionContext {
match notification {
Notification::Completed =>
if !self.model.is_ready.replace(true) {
info!(self.logger, "Context {self.id} Became ready");
info!("Context {} Became ready", self.id);
let this = self.clone();
executor::global::spawn(async move {
this.load_component_groups().await;
@ -287,7 +286,7 @@ impl model::execution_context::API for ExecutionContext {
visualization_id: VisualizationId,
data: VisualizationUpdateData,
) -> FallibleResult {
debug!(self.logger, "Dispatching visualization update through the context {self.id()}");
debug!("Dispatching visualization update through the context {}", self.id());
self.model.dispatch_visualization_update(visualization_id, data)
}
}
@ -296,11 +295,10 @@ impl Drop for ExecutionContext {
fn drop(&mut self) {
let id = self.id;
let ls = self.language_server.clone_ref();
let logger = self.logger.clone_ref();
executor::global::spawn(async move {
let result = ls.client.destroy_execution_context(&id).await;
if result.is_err() {
error!(logger, "Error when destroying Execution Context: {result:?}.");
error!("Error when destroying Execution Context: {result:?}.");
}
});
}

View File

@ -8,6 +8,7 @@ use ast::constants::LANGUAGE_FILE_EXTENSION;
use ast::constants::SOURCE_DIRECTORY;
use double_representation::definition::DefinitionInfo;
use double_representation::identifier::ReferentName;
use double_representation::module::ImportId;
use double_representation::project;
use engine_protocol::language_server::MethodPointer;
use flo_stream::Subscriber;
@ -26,7 +27,6 @@ pub mod plain;
pub mod synchronized;
pub use double_representation::module::Id;
use double_representation::module::ImportId;
pub use double_representation::module::QualifiedName;
pub use double_representation::tp::QualifiedName as TypeQualifiedName;
@ -75,7 +75,7 @@ pub enum ModulePathViolation {
// ===============
/// A specialization of text change used in module's text changes across controllers.
pub type TextChange = enso_text::Change<enso_text::unit::Bytes, String>;
pub type TextChange = enso_text::Change<enso_text::index::Byte, String>;
@ -289,7 +289,7 @@ pub enum NotificationKind {
/// The code change description.
change: TextChange,
/// Information about line:col position of replaced fragment.
replaced_location: enso_text::Range<enso_text::Location>,
replaced_location: enso_text::Range<enso_text::Location<enso_text::Byte>>,
},
/// The metadata (e.g. some node's position) has been changed.
MetadataChanged,
@ -469,7 +469,7 @@ impl Add for Position {
}
}
impl std::ops::AddAssign for Position {
impl AddAssign for Position {
fn add_assign(&mut self, rhs: Self) {
self.vector += rhs.vector
}
@ -739,9 +739,7 @@ pub mod test {
repository: Rc<model::undo_redo::Repository>,
) -> Module {
let ast = parser.parse_module(self.code.clone(), self.id_map.clone()).unwrap();
let logger = Logger::new("MockModule");
let module =
Plain::new(logger, self.path.clone(), ast, self.metadata.clone(), repository);
let module = Plain::new(self.path.clone(), ast, self.metadata.clone(), repository);
Rc::new(module)
}
}

View File

@ -35,7 +35,6 @@ use parser::Parser;
/// (text and graph).
#[derive(Debug)]
pub struct Module {
logger: Logger,
path: Path,
content: RefCell<Content>,
notifications: notification::Publisher<Notification>,
@ -45,14 +44,12 @@ pub struct Module {
impl Module {
/// Create state with given content.
pub fn new(
parent: impl AnyLogger,
path: Path,
ast: ast::known::Module,
metadata: Metadata,
repository: Rc<model::undo_redo::Repository>,
) -> Self {
Module {
logger: Logger::new_sub(parent, path.to_string()),
content: RefCell::new(ParsedSourceFile { ast, metadata }),
notifications: default(),
path,
@ -68,10 +65,10 @@ impl Module {
#[profile(Debug)]
fn set_content(&self, new_content: Content, kind: NotificationKind) -> FallibleResult {
if new_content == *self.content.borrow() {
debug!(self.logger, "Ignoring spurious update.");
debug!("Ignoring spurious update.");
return Ok(());
}
trace!(self.logger, "Updating module's content: {kind:?}. New content:\n{new_content}");
trace!("Updating module's content: {kind:?}. New content:\n{new_content}");
let transaction = self.repository.transaction("Setting module's content");
transaction.fill_content(self.id(), self.content.borrow().clone());
@ -174,9 +171,9 @@ impl model::module::API for Module {
parser: &Parser,
new_id_map: ast::IdMap,
) -> FallibleResult {
let mut code: enso_text::Text = self.ast().repr().into();
let replaced_start = code.location_of_byte_offset_snapped(change.range.start);
let replaced_end = code.location_of_byte_offset_snapped(change.range.end);
let mut code: enso_text::Rope = self.ast().repr().into();
let replaced_start = code.offset_to_location_snapped(change.range.start);
let replaced_end = code.offset_to_location_snapped(change.range.end);
let replaced_location = enso_text::Range::new(replaced_start, replaced_end);
code.apply_change(change.as_ref());
let new_ast = parser.parse(code.into(), new_id_map)?.try_into()?;
@ -284,14 +281,14 @@ mod test {
use crate::executor::test_utils::TestWithLocalPoolExecutor;
use crate::model::module::Position;
use enso_text::traits::*;
use enso_text::index::*;
#[wasm_bindgen_test]
fn applying_code_change() {
let _test = TestWithLocalPoolExecutor::set_up();
let module = model::module::test::plain_from_code("2 + 2");
let change = TextChange {
range: enso_text::Range::new(2.bytes(), 5.bytes()),
range: enso_text::Range::new(2.byte(), 5.byte()),
text: "- abc".to_string(),
};
module.apply_code_change(change, &Parser::new_or_panic(), default()).unwrap();
@ -322,13 +319,13 @@ mod test {
// Code change
let change = TextChange {
range: enso_text::Range::new(0.bytes(), 1.bytes()),
range: enso_text::Range::new(0.byte(), 1.byte()),
text: "foo".to_string(),
};
module.apply_code_change(change.clone(), &Parser::new_or_panic(), default()).unwrap();
let replaced_location = enso_text::Range {
start: enso_text::Location { line: 0.line(), column: 0.column() },
end: enso_text::Location { line: 0.line(), column: 1.column() },
start: enso_text::Location { line: 0.into(), offset: 0.byte() },
end: enso_text::Location { line: 0.into(), offset: 1.byte() },
};
expect_notification(NotificationKind::CodeChanged { change, replaced_location });

View File

@ -1,7 +1,7 @@
//! A Wrapper for module which synchronizes opening/closing and all changes with Language Server.
use crate::prelude::*;
use enso_text::unit::*;
use enso_text::index::*;
use crate::model::module::Content;
use crate::model::module::ImportMetadata;
@ -20,9 +20,9 @@ use double_representation::module::ImportId;
use engine_protocol::language_server;
use engine_protocol::language_server::TextEdit;
use engine_protocol::types::Sha3_224;
use enso_text::text;
use enso_text::Location;
use enso_text::Range;
use enso_text::Text;
use flo_stream::Subscriber;
use parser::api::SourceFile;
use parser::Parser;
@ -38,13 +38,17 @@ use parser::Parser;
#[derive(Clone, Debug, Eq, PartialEq)]
struct ContentSummary {
digest: Sha3_224,
end_of_file: Location,
/// The Engine's Locations are in java Characters, which are equal to UTF16 Code Units.
/// See https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html
end_of_file: Location<enso_text::Utf16CodeUnit>,
}
impl ContentSummary {
fn new(text: &Text) -> Self {
fn new(text: &text::Rope) -> Self {
let parts = text.rope.iter_chunks(..).map(|s| s.as_bytes());
Self { digest: Sha3_224::from_parts(parts), end_of_file: text.location_of_text_end() }
let end_location_bytes = text.last_line_end_location();
let end_of_file = text.utf16_code_unit_location_of_location(end_location_bytes);
Self { digest: Sha3_224::from_parts(parts), end_of_file }
}
}
@ -55,19 +59,20 @@ impl ContentSummary {
struct ParsedContentSummary {
#[shrinkwrap(main_field)]
summary: ContentSummary,
source: Text,
code: Range<Location>,
id_map: Range<Location>,
metadata: Range<Location>,
source: text::Rope,
code: Range<Location<Byte>>,
id_map: Range<Location<Byte>>,
metadata: Range<Location<Byte>>,
}
impl ParsedContentSummary {
/// Get summary from `SourceFile`.
fn from_source(source: &SourceFile) -> Self {
let content = Text::from(&source.content);
let code = source.code.map(|i| content.location_of_byte_offset_snapped(i));
let id_map = source.id_map.map(|i| content.location_of_byte_offset_snapped(i));
let metadata = source.metadata.map(|i| content.location_of_byte_offset_snapped(i));
let content = text::Rope::from(&source.content);
let to_location = |i: Byte| content.offset_to_location_snapped(i);
let code = source.code.map(to_location);
let id_map = source.id_map.map(to_location);
let metadata = source.metadata.map(to_location);
ParsedContentSummary {
summary: ContentSummary::new(&content),
source: content,
@ -78,23 +83,23 @@ impl ParsedContentSummary {
}
// Get fragment of string with code.
pub fn code_slice(&self) -> Text {
pub fn code_slice(&self) -> text::Rope {
self.slice(&self.code)
}
/// Get fragment of string with id map.
pub fn id_map_slice(&self) -> Text {
pub fn id_map_slice(&self) -> text::Rope {
self.slice(&self.id_map)
}
/// Get fragment of string with metadata.
pub fn metadata_slice(&self) -> Text {
pub fn metadata_slice(&self) -> text::Rope {
self.slice(&self.metadata)
}
fn slice(&self, range: &Range<Location>) -> Text {
let start_ix = self.source.byte_offset_of_location_snapped(range.start);
let end_ix = self.source.byte_offset_of_location_snapped(range.end);
fn slice(&self, range: &Range<Location<Byte>>) -> text::Rope {
let start_ix = self.source.location_offset_snapped(range.start);
let end_ix = self.source.location_offset_snapped(range.end);
self.source.sub(Range::new(start_ix, end_ix))
}
}
@ -135,7 +140,6 @@ impl LanguageServerContent {
pub struct Module {
model: model::module::Plain,
language_server: Rc<language_server::Connection>,
logger: Logger,
}
@ -153,21 +157,20 @@ impl Module {
parser: Parser,
repository: Rc<model::undo_redo::Repository>,
) -> FallibleResult<Rc<Self>> {
let logger = Logger::new(iformat!("Module {path}"));
let file_path = path.file_path().clone();
info!(logger, "Opening module {file_path}");
info!("Opening module {file_path}");
let opened = language_server.client.open_text_file(&file_path).await?;
let content: Text = (&opened.content).into();
info!(logger, "Read content of the module {path}, digest is {opened.current_version:?}");
let end_of_file = content.location_of_text_end();
let content: text::Rope = (&opened.content).into();
info!("Read content of the module {path}, digest is {:?}", opened.current_version);
let end_of_file_byte = content.last_line_end_location();
let end_of_file = content.utf16_code_unit_location_of_location(end_of_file_byte);
// TODO[ao] We should not fail here when metadata are malformed, but discard them and set
// default instead.
let source = parser.parse_with_metadata(opened.content)?;
let digest = opened.current_version;
let summary = ContentSummary { digest, end_of_file };
let model =
model::module::Plain::new(&logger, path, source.ast, source.metadata, repository);
let this = Rc::new(Module { model, language_server, logger });
let model = model::module::Plain::new(path, source.ast, source.metadata, repository);
let this = Rc::new(Module { model, language_server });
let content = this.model.serialized_content()?;
let first_invalidation = this.full_invalidation(&summary, content);
executor::global::spawn(Self::runner(this.clone_ref(), summary, first_invalidation));
@ -176,12 +179,11 @@ impl Module {
/// Create a module mock.
pub fn mock(model: model::module::Plain) -> Rc<Self> {
let logger = Logger::new(iformat!("Mocked Module {model.path()}"));
let client = language_server::MockClient::default();
client.expect.close_text_file(|_| Ok(()));
// We don't expect any other call, because we don't execute `runner()`.
let language_server = language_server::Connection::new_mock_rc(client);
Rc::new(Module { model, language_server, logger })
Rc::new(Module { model, language_server })
}
}
@ -299,7 +301,7 @@ impl Module {
let this = weak.upgrade();
match (notification, this) {
(Some(notification), Some(this)) => {
debug!(this.logger, "Processing a notification: {notification:?}");
debug!("Processing a notification: {notification:?}");
let result = this.handle_notification(&ls_content, notification).await;
ls_content = this.new_ls_content_info(ls_content.summary().clone(), result)
}
@ -320,11 +322,11 @@ impl Module {
) -> LanguageServerContent {
match new_content {
Ok(new_content) => {
debug!(self.logger, "Updating the LS content digest to: {new_content.summary:?}");
debug!("Updating the LS content digest to: {:?}", new_content.summary);
LanguageServerContent::Synchronized(new_content)
}
Err(err) => {
error!(self.logger, "Error during sending text change to Language Server: {err}");
error!("Error during sending text change to Language Server: {err}");
LanguageServerContent::Desynchronized(old_content)
}
}
@ -339,7 +341,9 @@ impl Module {
) -> FallibleResult<ParsedContentSummary> {
let Notification { new_file, kind, profiler } = notification;
let _profiler = profiler::start_debug!(profiler, "handle_notification");
debug!(self.logger, "Handling notification: {content:?}.");
debug!("Handling notification: {content:?}.");
let code = enso_text::Rope::from(self.model.serialized_content()?.content);
let to_engine_location = |l: Location<Byte>| code.utf16_code_unit_location_of_location(l);
match content {
LanguageServerContent::Desynchronized(summary) =>
profiler::await_!(self.full_invalidation(summary, new_file), _profiler),
@ -347,10 +351,12 @@ impl Module {
NotificationKind::Invalidate =>
profiler::await_!(self.partial_invalidation(summary, new_file), _profiler),
NotificationKind::CodeChanged { change, replaced_location } => {
let code_change =
TextEdit { range: replaced_location.into(), text: change.text };
let code_change = TextEdit {
range: replaced_location.map(to_engine_location).into(),
text: change.text,
};
let id_map_change = TextEdit {
range: summary.id_map.into(),
range: summary.id_map.map(to_engine_location).into(),
text: new_file.id_map_slice().to_string(),
};
//id_map goes first, because code change may alter its position.
@ -360,7 +366,7 @@ impl Module {
}
NotificationKind::MetadataChanged => {
let edits = vec![TextEdit {
range: summary.metadata.into(),
range: summary.metadata.map(to_engine_location).into(),
text: new_file.metadata_slice().to_string(),
}];
let notify_ls = self.notify_language_server(&summary.summary, &new_file, edits);
@ -378,20 +384,24 @@ impl Module {
ls_content: &ContentSummary,
new_file: SourceFile,
) -> impl Future<Output = FallibleResult<ParsedContentSummary>> + 'static {
debug!(self.logger, "Handling full invalidation: {ls_content:?}.");
debug!("Handling full invalidation: {ls_content:?}.");
let range = Range::new(Location::default(), ls_content.end_of_file);
let edits = vec![TextEdit { range: range.into(), text: new_file.content.clone() }];
self.notify_language_server(ls_content, &new_file, edits)
}
fn edit_for_snipped(start: &Location, source: Text, target: Text) -> Option<TextEdit> {
fn edit_for_snipped(
start: &Location<Byte>,
source: text::Rope,
target: text::Rope,
) -> Option<TextEdit> {
// This is an implicit assumption that always seems to be true. Otherwise finding the
// correct location for the final edit would be more complex.
debug_assert_eq!(start.column, 0.column());
debug_assert_eq!(start.offset, 0.byte());
let edit = TextEdit::from_prefix_postfix_differences(&source, &target);
(edit.range.start != edit.range.end || !edit.text.is_empty())
.as_some_from(|| edit.move_by_lines(start.line.as_usize()))
.as_some_from(|| edit.move_by_lines(start.line.value))
}
fn edit_for_code(ls_content: &ParsedContentSummary, new_file: &SourceFile) -> Option<TextEdit> {
@ -435,7 +445,7 @@ impl Module {
ls_content: &ParsedContentSummary,
new_file: SourceFile,
) -> impl Future<Output = FallibleResult<ParsedContentSummary>> + 'static {
debug!(self.logger, "Handling partial invalidation: {ls_content:?}.");
debug!("Handling partial invalidation: {ls_content:?}.");
let edits = vec![
//id_map and metadata go first, because code change may alter their position.
Self::edit_for_idmap(ls_content, &new_file),
@ -464,7 +474,7 @@ impl Module {
old_version: ls_content.digest.clone(),
new_version: Sha3_224::new(new_file.content.as_bytes()),
};
debug!(self.logger, "Notifying LS with edit: {edit:#?}.");
debug!("Notifying LS with edit: {edit:#?}.");
let ls_future_reply = self.language_server.client.apply_text_file_edit(&edit);
async move {
ls_future_reply.await?;
@ -477,11 +487,10 @@ impl Drop for Module {
fn drop(&mut self) {
let file_path = self.path().file_path().clone();
let language_server = self.language_server.clone_ref();
let logger = self.logger.clone_ref();
executor::global::spawn(async move {
let result = language_server.client.close_text_file(&file_path).await;
if let Err(err) = result {
error!(logger, "Error when closing module file {file_path}: {err}");
error!("Error when closing module file {file_path}: {err}");
}
});
}
@ -517,8 +526,8 @@ pub mod test {
use engine_protocol::language_server::MockClient;
use engine_protocol::language_server::Position;
use engine_protocol::language_server::TextRange;
use enso_text::text;
use enso_text::Change;
use enso_text::Text;
use json_rpc::error::RpcError;
use wasm_bindgen_test::wasm_bindgen_test;
@ -528,22 +537,19 @@ pub mod test {
// Ensures that subsequent LS text operations form a consistent series of versions.
#[derive(Clone, Debug)]
struct LsClientSetup {
logger: Logger,
path: Path,
current_ls_content: Rc<CloneCell<Text>>,
current_ls_content: Rc<CloneCell<text::Rope>>,
current_ls_version: Rc<CloneCell<Sha3_224>>,
}
impl LsClientSetup {
fn new(parent: impl AnyLogger, path: Path, initial_content: impl Into<Text>) -> Self {
fn new(path: Path, initial_content: impl Into<text::Rope>) -> Self {
let current_ls_content = initial_content.into();
let current_ls_version =
Sha3_224::from_parts(current_ls_content.iter_chunks(..).map(|ch| ch.as_bytes()));
let logger = Logger::new_sub(parent, "LsClientSetup");
debug!(logger, "Initial content:\n===\n{current_ls_content}\n===");
debug!("Initial content:\n===\n{current_ls_content}\n===");
Self {
path,
logger,
current_ls_content: Rc::new(CloneCell::new(current_ls_content)),
current_ls_version: Rc::new(CloneCell::new(current_ls_version)),
}
@ -551,7 +557,7 @@ pub mod test {
/// Create a setup initialized with the data from the given mock description.
fn new_for_mock_data(data: &crate::test::mock::Unified) -> Self {
Self::new(&data.logger, data.module_path.clone(), data.get_code())
Self::new(data.module_path.clone(), data.get_code())
}
/// Set up general text edit expectation in the mock client.
@ -572,18 +578,18 @@ pub mod test {
let actual_old = this.current_ls_version.get();
let actual_new =
Sha3_224::from_parts(new_content.iter_chunks(..).map(|s| s.as_bytes()));
debug!(this.logger, "Actual digest: {actual_old} => {actual_new}");
debug!(this.logger, "Declared digest: {edits.old_version} => {edits.new_version}");
debug!(this.logger, "New content:\n===\n{new_content}\n===");
debug!("Actual digest: {actual_old} => {actual_new}");
debug!("Declared digest: {} => {}", edits.old_version, edits.new_version);
debug!("New content:\n===\n{new_content}\n===");
assert_eq!(&edits.path, this.path.file_path());
assert_eq!(edits.old_version, actual_old);
assert_eq!(edits.new_version, actual_new);
if result.is_ok() {
this.current_ls_content.set(new_content);
this.current_ls_version.set(actual_new);
debug!(this.logger, "Accepted!");
debug!("Accepted!");
} else {
debug!(this.logger, "Rejected!");
debug!("Rejected!");
}
result
});
@ -603,8 +609,10 @@ pub mod test {
// TODO [mwu]
// Currently this assumes that the whole idmap is replaced at each edit.
// This code should be adjusted, if partial metadata updates are implemented.
let idmap_range =
file_so_far.id_map.map(|x| code_so_far.location_of_byte_offset_snapped(x));
let idmap_range = file_so_far.id_map.map(|x| {
let location_bytes = code_so_far.offset_to_location_snapped(x);
code_so_far.utf16_code_unit_location_of_location(location_bytes)
});
let idmap_range = TextRange::from(idmap_range);
assert_eq!(edit_idmap.range, idmap_range);
assert!(SourceFile::looks_like_idmap(&edit_idmap.text));
@ -640,21 +648,24 @@ pub mod test {
fn whole_document_range(&self) -> TextRange {
let code_so_far = self.current_ls_content.get();
let end_of_file = code_so_far.location_of_text_end();
let end_of_file_bytes = code_so_far.last_line_end_location();
let end_of_file = code_so_far.utf16_code_unit_location_of_location(end_of_file_bytes);
TextRange { start: Position { line: 0, character: 0 }, end: end_of_file.into() }
}
}
fn apply_edit(code: impl Into<Text>, edit: &TextEdit) -> Text {
fn apply_edit(code: impl Into<text::Rope>, edit: &TextEdit) -> text::Rope {
let mut code = code.into();
let start_loc = code.byte_offset_of_location_snapped(edit.range.start.into());
let end_loc = code.byte_offset_of_location_snapped(edit.range.end.into());
let change = Change { range: Range::new(start_loc, end_loc), text: edit.text.clone() };
let start = code.location_of_utf16_code_unit_location_snapped(edit.range.start.into());
let start_byte = code.location_offset_snapped(start);
let end = code.location_of_utf16_code_unit_location_snapped(edit.range.end.into());
let end_byte = code.location_offset_snapped(end);
let change = Change { range: Range::new(start_byte, end_byte), text: edit.text.clone() };
code.apply_change(change);
code
}
fn apply_edits(code: impl Into<Text>, file_edit: &FileEdit) -> Text {
fn apply_edits(code: impl Into<text::Rope>, file_edit: &FileEdit) -> text::Rope {
let initial = code.into();
file_edit.edits.iter().fold(initial, |content, edit| apply_edit(&content, edit))
}
@ -677,7 +688,7 @@ pub mod test {
// Parser which is time-consuming to construct.
let test = |runner: &mut Runner| {
let module_path = data.module_path.clone();
let edit_handler = Rc::new(LsClientSetup::new(&data.logger, module_path, initial_code));
let edit_handler = Rc::new(LsClientSetup::new(module_path, initial_code));
let mut fixture = data.fixture_customize(|data, client, _| {
data.expect_opening_module(client);
data.expect_closing_module(client);
@ -752,10 +763,10 @@ pub mod test {
#[test]
fn handle_insertion_edits_bug180558676() {
let source = Text::from("from Standard.Base import all\n\nmain =\n operator1 = 0.up_to 100 . to_vector . map .noise\n operator1.sort\n");
let target = Text::from("from Standard.Base import all\nimport Standard.Visualization\n\nmain =\n operator1 = 0.up_to 100 . to_vector . map .noise\n operator1.sort\n");
let source = text::Rope::from("from Standard.Base import all\n\nmain =\n operator1 = 0.up_to 100 . to_vector . map .noise\n operator1.sort\n");
let target = text::Rope::from("from Standard.Base import all\nimport Standard.Visualization\n\nmain =\n operator1 = 0.up_to 100 . to_vector . map .noise\n operator1.sort\n");
let edit = Module::edit_for_snipped(
&Location { line: 0.into(), column: 0.into() },
&Location { line: 0.into(), offset: 0.into() },
source,
target,
);

View File

@ -266,7 +266,7 @@ impl Project {
) -> FallibleResult<Self> {
let wrap = UnsupportedEngineVersion::error_wrapper(&properties);
let logger = Logger::new_sub(parent, "Project Controller");
info!(logger, "Creating a model of project {properties.name}");
info!("Creating a model of project {}", properties.name);
let binary_protocol_events = language_server_bin.event_stream();
let json_rpc_events = language_server_rpc.events();
let embedded_visualizations = default();
@ -375,36 +375,30 @@ impl Project {
pub fn binary_event_handler(
&self,
) -> impl Fn(engine_protocol::binary::Event) -> futures::future::Ready<()> {
let logger = self.logger.clone_ref();
let publisher = self.notifications.clone_ref();
let weak_execution_contexts = Rc::downgrade(&self.execution_contexts);
move |event| {
debug!(logger, "Received an event from the binary protocol: {event:?}");
debug!("Received an event from the binary protocol: {event:?}");
use engine_protocol::binary::client::Event;
use engine_protocol::binary::Notification;
match event {
Event::Notification(Notification::VisualizationUpdate { context, data }) => {
debug!(
logger,
"Visualization binary data: {String::from_utf8_lossy(data.as_ref())}"
);
debug!("Visualization binary data: {}", String::from_utf8_lossy(data.as_ref()));
let data = VisualizationUpdateData::new(data);
if let Some(execution_contexts) = weak_execution_contexts.upgrade() {
let result =
execution_contexts.dispatch_visualization_update(context, data);
if let Err(error) = result {
error!(logger, "Failed to handle the visualization update: {error}.");
error!("Failed to handle the visualization update: {error}.");
}
} else {
error!(
logger,
"Received a visualization update despite project being \
already dropped."
"Received a visualization update despite project being already dropped."
);
}
}
Event::Closed => {
error!(logger, "Lost binary connection with the Language Server!");
error!("Lost binary connection with the Language Server!");
let which = model::project::BackendConnection::LanguageServerBinary;
let notification = model::project::Notification::ConnectionLost(which);
publisher.notify(notification);
@ -413,7 +407,7 @@ impl Project {
// https://github.com/enso-org/ide/issues/145
}
Event::Error(error) => {
error!(logger, "Error emitted by the binary data connection: {error}.");
error!("Error emitted by the binary data connection: {error}.");
}
}
futures::future::ready(())
@ -427,16 +421,14 @@ impl Project {
pub fn execution_update_handler(
&self,
) -> impl Fn(execution_context::Id, ExecutionUpdate) + Clone {
let logger = self.logger.clone_ref();
let registry = Rc::downgrade(&self.execution_contexts);
move |id, update| {
if let Some(registry) = registry.upgrade() {
if let Err(error) = registry.handle_update(id, update) {
error!(logger, "Failed to handle the execution context update: {error}");
error!("Failed to handle the execution context update: {error}");
}
} else {
warning!(
logger,
warn!(
"Received an execution context notification despite execution \
context being already dropped."
);
@ -456,13 +448,12 @@ impl Project {
// generalize them, as the underlying RPC handlers and their types are separate.
// This generalization should be reconsidered once the old JSON-RPC handler is phased out.
// See: https://github.com/enso-org/ide/issues/587
let logger = self.logger.clone_ref();
let publisher = self.notifications.clone_ref();
let weak_suggestion_db = Rc::downgrade(&self.suggestion_db);
let weak_content_roots = Rc::downgrade(&self.content_roots);
let execution_update_handler = self.execution_update_handler();
move |event| {
debug!(logger, "Received an event from the json-rpc protocol: {event:?}");
debug!("Received an event from the json-rpc protocol: {event:?}");
use engine_protocol::language_server::Event;
use engine_protocol::language_server::Notification;
@ -489,9 +480,8 @@ impl Project {
}
Event::Notification(Notification::ExecutionFailed(update)) => {
error!(
logger,
"Execution failed in context {update.context_id}. Error: \
{update.message}."
"Execution failed in context {}. Error: {}.",
update.context_id, update.message
);
}
Event::Notification(Notification::SuggestionDatabaseUpdates(update)) =>
@ -510,14 +500,16 @@ impl Project {
}
Event::Notification(Notification::VisualisationEvaluationFailed(update)) => {
error!(
logger,
"Visualisation evaluation failed in context {update.context_id} \
for visualisation {update.visualisation_id} of expression \
{update.expression_id}. Error: {update.message}"
"Visualisation evaluation failed in context {} for visualisation {} of \
expression {}. Error: {}",
update.context_id,
update.visualisation_id,
update.expression_id,
update.message
);
}
Event::Closed => {
error!(logger, "Lost JSON-RPC connection with the Language Server!");
error!("Lost JSON-RPC connection with the Language Server!");
let which = model::project::BackendConnection::LanguageServerJson;
let notification = model::project::Notification::ConnectionLost(which);
publisher.notify(notification);
@ -526,7 +518,7 @@ impl Project {
// see https://github.com/enso-org/ide/issues/145
}
Event::Error(error) => {
error!(logger, "Error emitted by the JSON-RPC data connection: {error}.");
error!("Error emitted by the JSON-RPC data connection: {error}.");
}
}
futures::future::ready(())
@ -603,7 +595,7 @@ impl model::project::API for Project {
#[profile(Detail)]
fn module(&self, path: module::Path) -> BoxFuture<FallibleResult<model::Module>> {
async move {
info!(self.logger, "Obtaining module for {path}");
info!("Obtaining module for {path}");
let model_loader = self.load_module(path.clone());
let model: model::Module = self.module_registry.get_or_load(path, model_loader).await?;
Ok(model)

View File

@ -173,9 +173,7 @@ mod test {
let ast = ast::Ast::one_line_module(line).try_into().unwrap();
let path = ModulePath::from_mock_module_name("Test");
let urm = default();
let logger = Logger::new("Test");
let state =
Rc::new(model::module::Plain::new(logger, path.clone(), ast, default(), urm));
let state = Rc::new(model::module::Plain::new(path.clone(), ast, default(), urm));
let registry = Registry::default();
let expected = state.clone_ref();
@ -196,9 +194,7 @@ mod test {
let path1 = ModulePath::from_mock_module_name("Test");
let path2 = path1.clone();
let urm = default();
let logger = Logger::new("Test");
let state1 =
Rc::new(model::module::Plain::new(logger, path1.clone_ref(), ast, default(), urm));
let state1 = Rc::new(model::module::Plain::new(path1.clone_ref(), ast, default(), urm));
let state2 = state1.clone_ref();
let registry1 = Rc::new(Registry::default());
let registry2 = registry1.clone_ref();

View File

@ -4,13 +4,13 @@ use crate::prelude::*;
use crate::model::module::MethodId;
use crate::model::suggestion_database::entry::Kind;
use crate::model::suggestion_database::entry::ModuleSpan;
use crate::notification;
use ast::opr::predefined::ACCESS;
use double_representation::module::QualifiedName;
use engine_protocol::language_server;
use engine_protocol::language_server::SuggestionId;
use enso_text::Location;
use ensogl::data::HashMapTree;
use flo_stream::Subscriber;
use language_server::types::SuggestionDatabaseUpdatesEvent;
@ -58,7 +58,7 @@ impl QualifiedNameToIdMap {
let value = Some(id);
let old_value = self.replace_value_and_traverse_back_pruning_empty_subtrees(path, value);
if old_value.is_some() {
event!(WARN, "An existing suggestion entry id at {path} was overwritten with {id}.");
warn!("An existing suggestion entry id at {path} was overwritten with {id}.");
}
}
@ -70,7 +70,7 @@ impl QualifiedNameToIdMap {
let msg = format!(
"Could not remove a suggestion entry id at {path} because it does not exist."
);
event!(WARN, "{msg}");
warn!("{msg}");
}
}
@ -137,7 +137,6 @@ pub enum Notification {
/// argument names and types.
#[derive(Clone, Debug)]
pub struct SuggestionDatabase {
logger: Logger,
entries: RefCell<HashMap<entry::Id, Rc<Entry>>>,
qualified_name_to_id_map: RefCell<QualifiedNameToIdMap>,
examples: RefCell<Vec<Rc<Example>>>,
@ -147,22 +146,20 @@ pub struct SuggestionDatabase {
impl SuggestionDatabase {
/// Create a database with no entries.
pub fn new_empty(logger: impl AnyLogger) -> Self {
let logger = Logger::new_sub(logger, "SuggestionDatabase");
pub fn new_empty() -> Self {
let entries = default();
let qualified_name_to_id_map = default();
let examples = default();
let version = default();
let notifications = default();
Self { logger, entries, qualified_name_to_id_map, examples, version, notifications }
Self { entries, qualified_name_to_id_map, examples, version, notifications }
}
/// Create a database filled with entries provided by the given iterator.
pub fn new_from_entries<'a>(
logger: impl AnyLogger,
entries: impl IntoIterator<Item = (&'a SuggestionId, &'a Entry)>,
) -> Self {
let ret = Self::new_empty(logger);
let ret = Self::new_empty();
let entries = entries.into_iter().map(|(id, entry)| (*id, Rc::new(entry.clone())));
ret.entries.borrow_mut().extend(entries);
ret
@ -178,7 +175,6 @@ impl SuggestionDatabase {
/// Create a new database model from response received from the Language Server.
fn from_ls_response(response: language_server::response::GetSuggestionDatabase) -> Self {
let logger = Logger::new("SuggestionDatabase");
let mut entries = HashMap::new();
let mut qualified_name_to_id_map = QualifiedNameToIdMap::default();
for ls_entry in response.entries {
@ -189,7 +185,7 @@ impl SuggestionDatabase {
entries.insert(id, Rc::new(entry));
}
Err(err) => {
error!(logger, "Discarded invalid entry {id}: {err}");
error!("Discarded invalid entry {id}: {err}");
}
}
}
@ -197,12 +193,11 @@ impl SuggestionDatabase {
// available modules documentation. (https://github.com/enso-org/ide/issues/1011)
let examples = example::EXAMPLES.iter().cloned().map(Rc::new).collect_vec();
Self {
logger,
entries: RefCell::new(entries),
entries: RefCell::new(entries),
qualified_name_to_id_map: RefCell::new(qualified_name_to_id_map),
examples: RefCell::new(examples),
version: Cell::new(response.current_version),
notifications: default(),
examples: RefCell::new(examples),
version: Cell::new(response.current_version),
notifications: default(),
}
}
@ -228,7 +223,7 @@ impl SuggestionDatabase {
entries.insert(id, Rc::new(entry));
}
Err(err) => {
error!(self.logger, "Discarding update for {id}: {err}")
error!("Discarding update for {id}: {err}")
}
},
entry::Update::Remove { id } => {
@ -241,7 +236,7 @@ impl SuggestionDatabase {
"Received a suggestion database 'Remove' event for a nonexistent \
entry id: {id}."
);
error!(self.logger, "{msg}");
error!("{msg}");
}
}
}
@ -252,13 +247,10 @@ impl SuggestionDatabase {
let errors = entry.apply_modifications(*modification);
qn_to_id_map.set_and_warn_if_existed(&entry.qualified_name(), id);
for error in errors {
error!(
self.logger,
"Error when applying update for entry {id}: {error:?}"
);
error!("Error when applying update for entry {id}: {error:?}");
}
} else {
error!(self.logger, "Received Modify event for nonexistent id: {id}");
error!("Received Modify event for nonexistent id: {id}");
}
}
};
@ -300,39 +292,25 @@ impl SuggestionDatabase {
}
/// Search the database for entries with given name and visible at given location in module.
pub fn lookup_by_name_and_location(
&self,
name: impl Str,
module: &QualifiedName,
location: Location,
) -> Vec<Rc<Entry>> {
pub fn lookup_at(&self, name: impl Str, location: &ModuleSpan) -> Vec<Rc<Entry>> {
self.entries
.borrow()
.values()
.filter(|entry| {
entry.matches_name(name.as_ref()) && entry.is_visible_at(module, location)
})
.filter(|entry| entry.matches_name(name.as_ref()) && entry.is_visible_at(location))
.cloned()
.collect()
}
/// Search the database for Local or Function entries with given name and visible at given
/// location in module.
pub fn lookup_locals_by_name_and_location(
&self,
name: impl Str,
module: &QualifiedName,
location: Location,
) -> Vec<Rc<Entry>> {
pub fn lookup_locals_at(&self, name: impl Str, location: &ModuleSpan) -> Vec<Rc<Entry>> {
self.entries
.borrow()
.values()
.cloned()
.filter(|entry| {
let is_local = entry.kind == Kind::Function || entry.kind == Kind::Local;
is_local
&& entry.matches_name(name.as_ref())
&& entry.is_visible_at(module, location)
is_local && entry.matches_name(name.as_ref()) && entry.is_visible_at(location)
})
.collect()
}
@ -453,7 +431,8 @@ mod test {
use engine_protocol::language_server::SuggestionEntryScope;
use engine_protocol::language_server::SuggestionsDatabaseEntry;
use engine_protocol::language_server::SuggestionsDatabaseModification;
use enso_text::traits::*;
use enso_text::unit::*;
use enso_text::Location;
use wasm_bindgen_test::wasm_bindgen_test_configure;
wasm_bindgen_test_configure!(run_in_browser);
@ -698,9 +677,9 @@ mod test {
assert_eq!(db.lookup(3).unwrap().arguments[2].repr_type, "TestAtom");
assert!(db.lookup(3).unwrap().arguments[2].is_suspended);
assert_eq!(db.lookup(3).unwrap().arguments[2].default_value, None);
let range = Location { line: 1.line(), column: 5.column() }..=Location {
line: 3.line(),
column: 0.column(),
let range = Location { line: 1.into(), offset: Utf16CodeUnit::from(5) }..=Location {
line: 3.into(),
offset: Utf16CodeUnit::from(0),
};
assert_eq!(db.lookup(3).unwrap().scope, Scope::InModule { range });
assert_eq!(db.version.get(), 6);
@ -866,7 +845,7 @@ mod test {
// Check that the suggestion database doesn't panic when quering invalid qualified names.
#[test]
fn lookup_by_fully_qualified_name_with_invalid_names() {
let db = SuggestionDatabase::new_empty(Logger::new("SuggestionDatabase"));
let db = SuggestionDatabase::new_empty();
let _ = db.lookup_by_qualified_name_str("");
let _ = db.lookup_by_qualified_name_str(".");
let _ = db.lookup_by_qualified_name_str("..");

View File

@ -138,6 +138,23 @@ impl<'a> IntoIterator for &'a QualifiedName {
// ==================
// === ModuleSpan ===
// ==================
/// A span in a module identified by qualified name.
///
/// Span uses UTF-16 code units as units of measurement, so it is compatible with the format used
/// internally by the suggestion database entries.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ModuleSpan {
pub module: module::QualifiedName,
pub span: Location<enso_text::Utf16CodeUnit>,
}
// ================
// === IconName ===
// ================
@ -197,8 +214,12 @@ pub enum Scope {
Everywhere,
/// Local symbol that is visible only in a particular section of the module where it has been
/// defined.
///
/// We are using UTF-16 codepoints because this is what Language Server speaks.
/// To convert to bytes (or other system) one would need to know the whole module code which
/// is not available to the suggestions database.
#[allow(missing_docs)]
InModule { range: RangeInclusive<Location> },
InModule { range: RangeInclusive<Location<enso_text::Utf16CodeUnit>> },
}
/// Represents code snippet and the imports needed for it to work.
@ -325,10 +346,11 @@ impl Entry {
}
/// Checks if entry is visible at given location in a specific module.
pub fn is_visible_at(&self, module: &module::QualifiedName, location: Location) -> bool {
pub fn is_visible_at(&self, location: &ModuleSpan) -> bool {
let ModuleSpan { module, span } = location;
match &self.scope {
Scope::Everywhere => true,
Scope::InModule { range } => self.module == *module && range.contains(&location),
Scope::InModule { range } => self.module == *module && range.contains(span),
}
}
@ -361,7 +383,7 @@ impl Entry {
entry {self:?}. Every entry with the 'Method' kind should have a self \
type set, but this entry is missing the self type."
);
event!(ERROR, "{msg}");
error!("{msg}");
default()
}
},
@ -704,7 +726,7 @@ where I: IntoIterator<Item = &'a language_server::types::DocSection> {
documentation of a component is not a valid, losslessly-convertible snake_case \
identifier. The component may be displayed with a different icon than expected."
);
event!(WARN, "{msg}");
warn!("{msg}");
}
Some(icon_name)
}

View File

@ -107,12 +107,11 @@ impl Transaction {
pub fn fill_content(&self, id: model::module::Id, content: model::module::Content) {
with(self.frame.borrow_mut(), |mut data| {
debug!(
self.logger,
"Filling transaction '{data.name}' with snapshot of module '{id}':\
\n{content}"
"Filling transaction '{}' with snapshot of module '{id}':\n{content}",
data.name
);
if data.snapshots.try_insert(id, content).is_err() {
debug!(self.logger, "Skipping this snapshot, as module's state was already saved.")
debug!("Skipping this snapshot, as module's state was already saved.")
}
})
}
@ -122,7 +121,7 @@ impl Transaction {
/// Ignored transaction when dropped is discarded, rather than being put on top of "Redo" stack.
/// It does not affect the actions belonging to transaction in any way.
pub fn ignore(&self) {
debug!(self.logger, "Marking transaction '{self.frame.borrow().name}' as ignored.");
debug!("Marking transaction '{}' as ignored.", self.frame.borrow().name);
self.ignored.set(true)
}
}
@ -131,14 +130,13 @@ impl Drop for Transaction {
fn drop(&mut self) {
if let Some(urm) = self.urm.upgrade() {
if !self.ignored.get() {
info!(self.logger, "Transaction '{self.name()}' will create a new frame.");
info!("Transaction '{}' will create a new frame.", self.name());
urm.push_to(Stack::Undo, self.frame.borrow().clone());
urm.clear(Stack::Redo);
} else {
info!(
self.logger,
"Dropping the ignored transaction '{self.name()}' without \
pushing a frame to repository."
"Dropping the ignored transaction '{}' without pushing a frame to repository.",
self.name()
)
}
}
@ -249,7 +247,7 @@ impl Repository {
Err(ongoing_transaction)
} else {
let name = name.into();
debug!(self.logger, "Creating a new transaction `{name}`");
debug!("Creating a new transaction `{name}`");
let new_transaction = Rc::new(Transaction::new(self, name));
self.data.borrow_mut().current_transaction = Some(Rc::downgrade(&new_transaction));
Ok(new_transaction)
@ -300,13 +298,13 @@ impl Repository {
/// Push a new frame to the given stack.
fn push_to(&self, stack: Stack, frame: Frame) {
debug!(self.logger, "Pushing to {stack} stack a new frame: {frame}");
debug!("Pushing to {stack} stack a new frame: {frame}");
self.borrow_mut(stack).push(frame);
}
/// Clear all frames from the given stack.
fn clear(&self, stack: Stack) {
debug!(self.logger, "Clearing {stack} stack.");
debug!("Clearing {stack} stack.");
self.borrow_mut(stack).clear();
}
@ -328,9 +326,8 @@ impl Repository {
fn pop(&self, stack: Stack) -> FallibleResult<Frame> {
let frame = self.borrow_mut(stack).pop().ok_or(NoFrameToPop(stack))?;
debug!(
self.logger,
"Popping a frame from {stack}. Remaining length: {self.len(stack)}. \
Frame: {frame}"
"Popping a frame from {stack}. Remaining length: {}. Frame: {frame}",
self.len(stack)
);
Ok(frame)
}
@ -388,7 +385,7 @@ impl Manager {
/// Undo last operation.
pub fn undo(&self) -> FallibleResult {
debug!(self.logger, "Undo requested, stack size is {self.repository.len(Stack::Undo)}.");
debug!("Undo requested, stack size is {}.", self.repository.len(Stack::Undo));
let frame = self.repository.last(Stack::Undo)?;
// Before applying undo we create a special transaction. The purpose it two-fold:
@ -411,7 +408,7 @@ impl Manager {
// supposed to stay on top, as we maintain an open transaction while undoing.
if !popped.contains(&frame) {
// No reason to stop the world but should catch our eye in logs.
error!(self.logger, "Undone frame mismatch!");
error!("Undone frame mismatch!");
debug_assert!(false, "Undone frame mismatch!");
}
@ -433,7 +430,7 @@ impl Manager {
/// Restore all modules affected by the [`Frame`] to their stored state.
fn reset_to(&self, frame: &Frame) -> FallibleResult {
info!(self.logger, "Resetting to initial state on frame {frame}");
info!("Resetting to initial state on frame {frame}");
// First we must have all modules resolved. Only then we can start applying changes.
// Otherwise, if one of the modules could not be retrieved, we'd risk ending up with
@ -454,7 +451,7 @@ impl Manager {
})?;
for (module, content) in module_and_content {
info!(self.logger, "Undoing on module {module.path()}");
info!("Undoing on module {}", module.path());
// The below should never fail, because it can fail only if serialization to code fails.
// And it cannot fail, as it already underwent this procedure successfully in the past
// (we are copying an old state, so it must ba a representable state).
@ -561,14 +558,13 @@ main =
use model::module::Position;
let mut fixture = crate::test::mock::Unified::new().fixture();
let Fixture { executed_graph, graph, project, logger, .. } = &mut fixture;
let logger: &Logger = logger;
let Fixture { executed_graph, graph, project, .. } = &mut fixture;
let urm = project.urm();
let nodes = executed_graph.graph().nodes().unwrap();
let node = &nodes[0];
debug!(logger, "{node.position():?}");
debug!("{:?}", node.position());
let pos1 = Position::new(500.0, 250.0);
let pos2 = Position::new(300.0, 150.0);

View File

@ -35,7 +35,6 @@ pub use searcher::Searcher;
#[derive(Debug)]
struct Model {
logger: Logger,
current_project: RefCell<Option<Project>>,
controller: controller::Ide,
view: view::root::View,
@ -76,7 +75,7 @@ impl Model {
}
Err(err) => {
let err_msg = format!("Failed to initialize project: {}", err);
error!(self.logger, "{err_msg}");
error!("{err_msg}");
self.controller.status_notifications().publish_event(err_msg);
}
}
@ -87,15 +86,14 @@ impl Model {
/// a second one for opening the project.
#[profile(Task)]
pub fn open_project(&self, project_name: String) {
let logger = self.logger.clone_ref();
let controller = self.controller.clone_ref();
crate::executor::global::spawn(async move {
if let Ok(managing_api) = controller.manage_projects() {
if let Err(err) = managing_api.open_project_by_name(project_name).await {
error!(logger, "Cannot open project by name: {err}.");
error!("Cannot open project by name: {err}.");
}
} else {
warning!(logger, "Project opening failed: no ProjectManagingAPI available.");
warn!("Project opening failed: no ProjectManagingAPI available.");
}
});
}
@ -104,23 +102,19 @@ impl Model {
/// Engine. It makes a call to Project Manager.
#[profile(Task)]
fn create_project(&self, template: Option<&str>) {
let logger = self.logger.clone_ref();
let controller = self.controller.clone_ref();
let template = template.map(ToOwned::to_owned);
crate::executor::global::spawn(async move {
if let Ok(managing_api) = controller.manage_projects() {
if let Err(err) = managing_api.create_new_project(template.clone()).await {
if let Some(template) = template {
error!(
logger,
"Could not create new project from template {template}: {err}."
);
error!("Could not create new project from template {template}: {err}.");
} else {
error!(logger, "Could not create new project: {err}.");
error!("Could not create new project: {err}.");
}
}
} else {
warning!(logger, "Project creation failed: no ProjectManagingAPI available.");
warn!("Project creation failed: no ProjectManagingAPI available.");
}
});
}
@ -148,9 +142,8 @@ impl Presenter {
/// project will be displayed (if any).
#[profile(Task)]
pub fn new(controller: controller::Ide, view: ide_view::root::View) -> Self {
let logger = Logger::new("Presenter");
let current_project = default();
let model = Rc::new(Model { logger, controller, view, current_project });
let model = Rc::new(Model { controller, view, current_project });
frp::new_network! { network
let welcome_view_frp = &model.view.welcome_screen().frp;
@ -179,7 +172,6 @@ impl Presenter {
use controller::ide::BackgroundTaskHandle as ControllerHandle;
use ide_view::status_bar::process::Id as ViewHandle;
let logger = self.model.logger.clone_ref();
let process_map = SharedHashMap::<ControllerHandle, ViewHandle>::new();
let status_bar = self.model.view.status_bar().clone_ref();
let status_notifications = self.model.controller.status_notifications().subscribe();
@ -198,7 +190,7 @@ impl Presenter {
if let Some(view_handle) = process_map.remove(&handle) {
status_bar.finish_process(view_handle);
} else {
warning!(logger, "Controllers finished process not displayed in view");
warn!("Controllers finished process not displayed in view");
}
}
}
@ -228,7 +220,7 @@ impl Presenter {
self.model.view.welcome_screen().frp.set_projects_list(names);
}
Err(err) => {
error!(self.model.logger, "Unable to get list of projects: {err}.");
error!("Unable to get list of projects: {err}.");
}
}
}

View File

@ -17,21 +17,19 @@ use ide_view as view;
#[derive(Debug)]
struct Model {
logger: Logger,
controller: controller::Text,
view: view::code_editor::View,
}
impl Model {
fn new(controller: controller::Text, view: view::code_editor::View) -> Self {
let logger = Logger::new("presenter::code");
Self { logger, controller, view }
Self { controller, view }
}
fn apply_change_from_view(&self, change: &enso_text::Change) {
let converted = enso_text::Change { range: change.range, text: change.text.to_string() };
if let Err(err) = self.controller.apply_text_change(converted) {
error!(self.logger, "Error while applying text change: {err}");
error!("Error while applying text change: {err}");
}
}
@ -40,17 +38,16 @@ impl Model {
match self.controller.read_content().await {
Ok(code) => endpoint.emit(ImString::new(code)),
Err(err) => {
error!(self.logger, "Error while updating code editor: {err}")
error!("Error while updating code editor: {err}")
}
}
}
fn save_module(&self, content: String) {
let logger = self.logger.clone_ref();
let controller = self.controller.clone_ref();
executor::global::spawn(async move {
if let Err(err) = controller.store_content(content).await {
error!(logger, "Error while saving module: {err}");
error!("Error while saving module: {err}");
}
})
}
@ -83,9 +80,9 @@ impl Code {
desynchronized <- all_with(&code_in_controller, &text_area.content, |controller, view|
*controller != view.to_string()
);
text_area.set_content <+ code_in_controller.gate(&desynchronized).map(|s| s.to_string());
text_area.set_content <+ code_in_controller.gate(&desynchronized);
maybe_change_to_apply <= text_area.changed;
maybe_change_to_apply <= text_area.changed.map(|c| (**c).clone());
change_to_apply <- maybe_change_to_apply.gate(&desynchronized);
eval change_to_apply ((change) model.apply_change_from_view(change));

View File

@ -101,7 +101,7 @@ impl Model {
state.clone_ref(),
);
let execution_stack =
CallStack::new(&logger, controller.clone_ref(), view.clone_ref(), state.clone_ref());
CallStack::new(controller.clone_ref(), view.clone_ref(), state.clone_ref());
Self {
logger,
project,
@ -184,7 +184,7 @@ impl Model {
fn nodes_collapsed(&self, collapsed: &[ViewNodeId]) {
self.log_action(
|| {
debug!(self.logger, "Collapsing node.");
debug!("Collapsing node.");
let ids = collapsed.iter().filter_map(|node| self.state.ast_node_id_of_view(*node));
let new_node_id = self.controller.graph().collapse(ids, COLLAPSED_FUNCTION_NAME);
// TODO [mwu] https://github.com/enso-org/ide/issues/760
@ -199,7 +199,7 @@ impl Model {
fn log_action<F>(&self, f: F, action: &str)
where F: FnOnce() -> Option<FallibleResult> {
if let Some(Err(err)) = f() {
error!(self.logger, "Failed to {action} in AST: {err}");
error!("Failed to {action} in AST: {err}");
}
}
@ -296,7 +296,7 @@ impl Model {
let position = model::module::Position { vector: position };
let handler = NodeFromDroppedFileHandler::new(&self.logger, project, graph);
if let Err(err) = handler.create_node_and_start_uploading(to_upload, position) {
error!(self.logger, "Error when creating node from dropped file: {err}");
error!("Error when creating node from dropped file: {err}");
}
}
@ -481,7 +481,6 @@ impl Graph {
#[profile(Detail)]
fn init(self, project_view: &view::project::View) -> Self {
let logger = &self.model.logger;
let network = &self.network;
let model = &self.model;
let view = &self.model.view.frp;
@ -490,10 +489,10 @@ impl Graph {
// Position initialization should go before emitting `update_data` event.
update_with_gap <- view.default_y_gap_between_nodes.sample(&update_view);
eval update_with_gap ((gap) model.initialize_nodes_positions(*gap));
update_data <- update_view.map(f_!([logger,model] match ViewUpdate::new(&*model) {
update_data <- update_view.map(f_!([model] match ViewUpdate::new(&*model) {
Ok(update) => Rc::new(update),
Err(err) => {
error!(logger,"Failed to update view: {err:?}");
error!("Failed to update view: {err:?}");
Rc::new(default())
}
}));

View File

@ -19,7 +19,6 @@ use ide_view as view;
#[derive(Debug)]
struct Model {
logger: Logger,
controller: controller::ExecutedGraph,
view: view::graph_editor::GraphEditor,
state: Rc<State>,
@ -27,13 +26,11 @@ struct Model {
impl Model {
fn new(
parent: impl AnyLogger,
controller: controller::ExecutedGraph,
view: view::graph_editor::GraphEditor,
state: Rc<State>,
) -> Self {
let logger = parent.sub("presenter::graph::CallStack");
Self { logger, controller, view, state }
Self { controller, view, state }
}
fn expression_entered(&self, local_call: &view::graph_editor::LocalCall) {
@ -45,7 +42,7 @@ impl Model {
}
fn node_entered(&self, node_id: ViewNodeId) {
debug!(self.logger, "Requesting entering the node {node_id}.");
debug!("Requesting entering the node {node_id}.");
analytics::remote_log_event("integration::node_entered");
if let Some(call) = self.state.ast_node_id_of_view(node_id) {
match self.controller.node_method_pointer(call) {
@ -54,31 +51,29 @@ impl Model {
let local_call = LocalCall { call, definition };
self.enter_expression(local_call);
}
Err(_) =>
info!(self.logger, "Ignoring request to enter non-enterable node {call}."),
Err(_) => info!("Ignoring request to enter non-enterable node {call}."),
}
} else {
error!(self.logger, "Cannot enter {node_id:?}: no AST node bound to the view.");
error!("Cannot enter {node_id:?}: no AST node bound to the view.");
}
}
fn node_exited(&self) {
debug!(self.logger, "Requesting exiting the current node.");
debug!("Requesting exiting the current node.");
analytics::remote_log_event("integration::node_exited");
let controller = self.controller.clone_ref();
let logger = self.logger.clone_ref();
let store_stack = self.store_updated_stack_task();
executor::global::spawn(async move {
info!(logger, "Exiting node.");
info!("Exiting node.");
match controller.exit_node().await {
Ok(()) =>
if let Err(err) = store_stack() {
// We cannot really do anything when updating metadata fails.
// Can happen in improbable case of serialization failure.
error!(logger, "Failed to store an updated call stack: {err}");
error!("Failed to store an updated call stack: {err}");
},
Err(err) => {
error!(logger, "Exiting node failed: {err}");
error!("Exiting node failed: {err}");
let event = "integration::exiting_node_failed";
let field = "error";
@ -91,19 +86,18 @@ impl Model {
fn enter_expression(&self, local_call: LocalCall) {
let controller = self.controller.clone_ref();
let logger = self.logger.clone_ref();
let store_stack = self.store_updated_stack_task();
executor::global::spawn(async move {
info!(logger, "Entering expression {local_call:?}.");
info!("Entering expression {local_call:?}.");
match controller.enter_method_pointer(&local_call).await {
Ok(()) =>
if let Err(err) = store_stack() {
// We cannot really do anything when updating metadata fails.
// Can happen in improbable case of serialization failure.
error!(logger, "Failed to store an updated call stack: {err}");
error!("Failed to store an updated call stack: {err}");
},
Err(err) => {
error!(logger, "Entering node failed: {err}.");
error!("Entering node failed: {err}.");
let event = "integration::entering_node_failed";
let field = "error";
let data = analytics::AnonymousData(|| err.to_string());
@ -149,13 +143,12 @@ pub struct CallStack {
impl CallStack {
/// Constructor. The returned presenter works right away.
pub fn new(
parent: impl AnyLogger,
controller: controller::ExecutedGraph,
view: view::graph_editor::GraphEditor,
state: Rc<State>,
) -> Self {
let network = frp::Network::new("presenter::graph::CallStack");
let model = Rc::new(Model::new(parent, controller, view, state));
let model = Rc::new(Model::new(controller, view, state));
let view = &model.view;
let breadcrumbs = &view.model.breadcrumbs;
@ -181,7 +174,7 @@ impl CallStack {
let graph_notifications = self.model.controller.subscribe();
let weak = Rc::downgrade(&self.model);
spawn_stream_handler(weak, graph_notifications, move |notification, model| {
info!(model.logger, "Received controller notification {notification:?}");
info!("Received controller notification {notification:?}");
match notification {
Notification::EnteredNode(frame) => model.add_breadcrumb_in_view(frame),
Notification::SteppedOutOfNode(_) => model.view.model.breadcrumbs.pop_breadcrumb(),

View File

@ -86,10 +86,7 @@ impl Model {
if let Some(target_id) = self.state.ast_node_id_of_view(node_id) {
manager.set_visualization(target_id, metadata);
} else {
error!(
self.logger,
"Failed to update visualization: {node_id:?} does not represent any AST code."
)
error!("Failed to update visualization: {node_id:?} does not represent any AST code.")
}
}
@ -110,7 +107,7 @@ impl Model {
Err(err) => {
// TODO [mwu]: We should consider having the visualization also accept error
// input.
error!(self.logger, "Failed to deserialize visualization update: {err}");
error!("Failed to deserialize visualization update: {err}");
}
}
}
@ -134,7 +131,6 @@ impl Model {
#[profile(Detail)]
fn load_visualizations(&self) {
self.graph_view.reset_visualization_registry();
let logger = self.logger.clone_ref();
let controller = self.controller.clone_ref();
let graph_editor = self.graph_view.clone_ref();
executor::global::spawn(async move {
@ -146,11 +142,11 @@ impl Model {
graph_editor.frp.register_visualization.emit(Some(visualization));
}
Err(err) => {
error!(logger, "Error while loading visualization {identifier}: {err:?}");
error!("Error while loading visualization {identifier}: {err:?}");
}
}
}
info!(logger, "Visualizations Initialized.");
info!("Visualizations Initialized.");
});
}
}
@ -181,8 +177,8 @@ impl Visualization {
let network = frp::Network::new("presenter::graph::Visualization");
let controller = project.visualization().clone_ref();
let (manager, notifications) = Manager::new(&logger, graph.clone_ref());
let (error_manager, error_notifications) = Manager::new(&logger, graph.clone_ref());
let (manager, notifications) = Manager::new(graph.clone_ref());
let (error_manager, error_notifications) = Manager::new(graph.clone_ref());
let model = Rc::new(Model {
logger,
controller,
@ -231,18 +227,17 @@ impl Visualization {
) -> Self {
let weak = Rc::downgrade(&self.model);
spawn_stream_handler(weak, notifier, move |notification, model| {
let logger = &model.logger;
info!(logger, "Received update for visualization: {notification:?}");
info!("Received update for visualization: {notification:?}");
match notification {
manager::Notification::ValueUpdate { target, data, .. } => {
model.handle_value_update(&update_endpoint, target, data);
}
manager::Notification::FailedToAttach { visualization, error } => {
error!(logger, "Visualization {visualization.id} failed to attach: {error}.");
error!("Visualization {} failed to attach: {error}.", visualization.id);
model.handle_controller_failure(&failure_endpoint, visualization.expression_id);
}
manager::Notification::FailedToDetach { visualization, error } => {
error!(logger, "Visualization {visualization.id} failed to detach: {error}.");
error!("Visualization {} failed to detach: {error}.", visualization.id);
// Here we cannot really do much. Failing to detach might mean that
// visualization was already detached, that we detached it
// but failed to observe this (e.g. due to a connectivity
@ -251,13 +246,13 @@ impl Visualization {
// it rather than likely break visualizations on the node altogether.
let forgotten = manager.forget_visualization(visualization.expression_id);
if let Some(forgotten) = forgotten {
error!(logger, "The visualization will be forgotten: {forgotten:?}")
error!("The visualization will be forgotten: {forgotten:?}")
}
}
manager::Notification::FailedToModify { desired, error } => {
error!(
logger,
"Visualization {desired.id} failed to be modified: {error}. Will hide it in GUI."
"Visualization {} failed to be modified: {error}. Will hide it in GUI.",
desired.id
);
// Actually it would likely have more sense if we had just restored the previous
// visualization, as its LS state should be preserved. However, we already
@ -287,10 +282,7 @@ impl Visualization {
model.error_manager.retain_visualizations(&nodes_set);
}
Err(err) => {
error!(
model.logger,
"Cannot update visualization after graph change: {err}"
);
error!("Cannot update visualization after graph change: {err}");
}
},
_ => {}

View File

@ -204,7 +204,6 @@ impl Description {
/// As this type wraps asynchronous operations, it should be stored using `Rc` pointer.
#[derive(Debug)]
pub struct Manager {
logger: Logger,
visualizations: SharedHashMap<ast::Id, Description>,
executed_graph: ExecutedGraph,
notification_sender: futures::channel::mpsc::UnboundedSender<Notification>,
@ -215,13 +214,9 @@ impl Manager {
///
/// Return a handle to the Manager and the receiver for notifications.
/// Note that receiver cannot be re-retrieved or changed in the future.
pub fn new(
logger: impl AnyLogger,
executed_graph: ExecutedGraph,
) -> (Rc<Self>, UnboundedReceiver<Notification>) {
let logger = logger.sub("visualization::Manager");
pub fn new(executed_graph: ExecutedGraph) -> (Rc<Self>, UnboundedReceiver<Notification>) {
let (notification_sender, notification_receiver) = futures::channel::mpsc::unbounded();
let ret = Self { logger, visualizations: default(), executed_graph, notification_sender };
let ret = Self { visualizations: default(), executed_graph, notification_sender };
(Rc::new(ret), notification_receiver)
}
@ -300,7 +295,7 @@ impl Manager {
}
fn write_new_desired(self: &Rc<Self>, target: ast::Id, new_desired: Option<Desired>) {
debug!(self.logger, "Requested to set visualization {target}: {new_desired:?}");
debug!("Requested to set visualization {target}: {new_desired:?}");
let mut current = match self.visualizations.get_cloned(&target) {
None => {
if new_desired.is_none() {
@ -319,7 +314,6 @@ impl Manager {
self.synchronize(target);
} else {
debug!(
self.logger,
"Visualization for {target} was already in the desired state: \
{new_desired:?}"
);
@ -368,7 +362,7 @@ impl Manager {
let desired_vis_id = description.desired.as_ref().map(|v| v.visualization_id);
let new_visualization = description.desired.and_then(|desired| {
this.prepare_visualization(desired.clone()).handle_err(|error| {
error!(this.logger, "Failed to prepare visualization {desired:?}: {error}")
error!("Failed to prepare visualization {desired:?}: {error}")
})
});
match (status, new_visualization) {
@ -396,10 +390,7 @@ impl Manager {
target: ast::Id,
new_visualization: Visualization,
) {
info!(
self.logger,
"Will attach visualization {new_visualization.id} to expression {target}"
);
info!("Will attach visualization {} to expression {target}", new_visualization.id);
let status = Status::BeingAttached(new_visualization.clone());
self.update_status(target, status);
let notifier = self.notification_sender.clone();
@ -435,7 +426,7 @@ impl Manager {
#[profile(Detail)]
async fn detach_visualization(self: Rc<Self>, target: ast::Id, so_far: Visualization) {
info!(self.logger, "Will detach from {target}: {so_far:?}");
info!("Will detach from {target}: {so_far:?}");
let status = Status::BeingDetached(so_far.clone());
self.update_status(target, status);
let detaching_result = self.executed_graph.detach_visualization(so_far.id);
@ -467,10 +458,7 @@ impl Manager {
so_far: Visualization,
new_visualization: Visualization,
) {
info!(
self.logger,
"Will modify visualization on {target} from {so_far:?} to {new_visualization:?}"
);
info!("Will modify visualization on {target} from {so_far:?} to {new_visualization:?}");
let status =
Status::BeingModified { from: so_far.clone(), to: new_visualization.clone() };
self.update_status(target, status);
@ -615,8 +603,7 @@ mod tests {
inner.project.clone_ref(),
execution_context,
);
let logger: Logger = inner.logger.sub("manager");
let (manager, notifier) = Manager::new(logger, executed_graph.clone_ref());
let (manager, notifier) = Manager::new(executed_graph.clone_ref());
Self { inner, is_ready, manager, notifier, requests }
}
}

View File

@ -82,7 +82,7 @@ impl Model {
*self.searcher.borrow_mut() = Some(searcher);
}
Err(err) => {
error!(self.logger, "Error while creating searcher integration: {err}");
error!("Error while creating searcher integration: {err}");
}
}
}
@ -145,11 +145,10 @@ impl Model {
if self.controller.model.name() != name.as_ref() {
let project = self.controller.model.clone_ref();
let breadcrumbs = self.view.graph().model.breadcrumbs.clone_ref();
let logger = self.logger.clone_ref();
let name = name.into();
executor::global::spawn(async move {
if let Err(e) = project.rename_project(name).await {
error!(logger, "The project couldn't be renamed: {e}");
error!("The project couldn't be renamed: {e}");
breadcrumbs.cancel_project_name_editing.emit(());
}
});
@ -157,16 +156,16 @@ impl Model {
}
fn undo(&self) {
debug!(self.logger, "Undo triggered in UI.");
debug!("Undo triggered in UI.");
if let Err(e) = self.controller.model.urm().undo() {
error!(self.logger, "Undo failed: {e}");
error!("Undo failed: {e}");
}
}
fn redo(&self) {
debug!(self.logger, "Redo triggered in UI.");
debug!("Redo triggered in UI.");
if let Err(e) = self.controller.model.urm().redo() {
error!(self.logger, "Redo failed: {e}");
error!("Redo failed: {e}");
}
}
}
@ -270,7 +269,7 @@ impl Project {
let notifications = self.model.controller.model.subscribe();
let weak = Rc::downgrade(&self.model);
spawn_stream_handler(weak, notifications, |notification, model| {
info!(model.logger, "Processing notification {notification:?}");
info!("Processing notification {notification:?}");
let message = match notification {
model::project::Notification::ConnectionLost(_) =>
crate::BACKEND_DISCONNECTED_MESSAGE,

View File

@ -139,7 +139,7 @@ impl Model {
}
fn create_providers(&self) -> provider::Any {
provider::create_providers_from_controller(&self.logger, &self.controller)
provider::create_providers_from_controller(&self.controller)
}
fn suggestion_for_entry_id(&self, id: list_panel::EntryId) -> FallibleResult<Suggestion> {

View File

@ -26,7 +26,7 @@ pub type Any = (
);
/// Create providers from the current controller's action list.
pub fn create_providers_from_controller(logger: &Logger, controller: &controller::Searcher) -> Any {
pub fn create_providers_from_controller(controller: &controller::Searcher) -> Any {
use controller::searcher::Actions;
match controller.actions() {
Actions::Loading => as_any(Rc::new(list_view::entry::EmptyProvider)),
@ -37,7 +37,7 @@ pub fn create_providers_from_controller(logger: &Logger, controller: &controller
as_any(Rc::new(provider))
}
Actions::Error(err) => {
error!(logger, "Error while obtaining searcher action list: {err}");
error!("Error while obtaining searcher action list: {err}");
as_any(Rc::new(list_view::entry::EmptyProvider))
}
}
@ -106,8 +106,8 @@ impl list_view::entry::ModelProvider<GlyphHighlightedLabel> for Action {
if let Some(char) = char_iter.next() {
let (char_idx, (byte_id, char)) = char;
if char_idx == *idx {
let start = enso_text::unit::Bytes(byte_id as i32);
let end = enso_text::unit::Bytes((byte_id + char.len_utf8()) as i32);
let start = enso_text::index::Byte(byte_id);
let end = enso_text::index::Byte(byte_id + char.len_utf8());
break Some(enso_text::Range::new(start, end));
}
} else {
@ -207,7 +207,7 @@ impl list_view::entry::ModelProvider<component_group_view::Entry> for Component
// === Component Provider helpers ===
fn bytes_of_matched_letters(match_info: &MatchInfo, label: &str) -> Vec<text::Range<text::Bytes>> {
fn bytes_of_matched_letters(match_info: &MatchInfo, label: &str) -> Vec<text::Range<text::Byte>> {
if let MatchInfo::Matches { subsequence } = match_info {
let mut char_iter = label.char_indices().enumerate();
subsequence
@ -217,8 +217,8 @@ fn bytes_of_matched_letters(match_info: &MatchInfo, label: &str) -> Vec<text::Ra
if let Some(char) = char_iter.next() {
let (char_idx, (byte_id, char)) = char;
if char_idx == *idx {
let start = enso_text::unit::Bytes(byte_id as i32);
let end = enso_text::unit::Bytes((byte_id + char.len_utf8()) as i32);
let start = enso_text::index::Byte(byte_id);
let end = enso_text::index::Byte(byte_id + char.len_utf8());
break Some(enso_text::Range::new(start, end));
}
} else {

View File

@ -191,9 +191,7 @@ pub mod mock {
let path = self.module_path.clone();
let metadata = self.metadata.clone();
let repository = urm.repository.clone_ref();
let logger = &self.logger;
let module =
Rc::new(model::module::Plain::new(logger, path, ast, metadata, repository));
let module = Rc::new(model::module::Plain::new(path, ast, metadata, repository));
urm.module_opened(module.clone());
module
}
@ -230,8 +228,7 @@ pub mod mock {
}
pub fn execution_context(&self) -> Rc<model::execution_context::Plain> {
let logger = Logger::new_sub(&self.logger, "Mocked Execution Context");
Rc::new(model::execution_context::Plain::new(logger, self.method_pointer()))
Rc::new(model::execution_context::Plain::new(self.method_pointer()))
}
pub fn project(
@ -282,7 +279,7 @@ pub mod mock {
let urm = self.undo_redo_manager();
let module = self.module(urm.clone());
let suggestion_db =
Rc::new(model::SuggestionDatabase::new_from_entries(&logger, &self.suggestions));
Rc::new(model::SuggestionDatabase::new_from_entries(&self.suggestions));
let graph = self.graph(&logger, module.clone_ref(), suggestion_db.clone_ref());
let execution = self.execution_context();
let project = self.project(

View File

@ -235,7 +235,7 @@ impl Model {
}
let url = self.socket.url();
info!(self.logger, "Reconnecting WS to {url}.");
info!("Reconnecting WS to {url}.");
let new_ws = web_sys::WebSocket::new(&url)?;
@ -252,12 +252,9 @@ impl Model {
impl Drop for Model {
fn drop(&mut self) {
info!(self.logger, "Dropping WS model.");
info!("Dropping WS model.");
if let Err(e) = self.close("Rust Value has been dropped.") {
error!(
self.logger,
"Error when closing socket due to being dropped: {e.print_to_string()}"
)
error!("Error when closing socket due to being dropped: {}", e.print_to_string())
}
}
}
@ -299,11 +296,10 @@ impl WebSocket {
/// Generate a callback to be invoked when socket needs reconnecting.
fn reconnect_trigger(&self) -> impl FnMut(web_sys::CloseEvent) {
let model = Rc::downgrade(&self.model);
let logger = self.logger.clone();
move |_| {
if let Some(model) = model.upgrade() {
if let Err(e) = model.borrow_mut().reconnect() {
error!(logger, "Failed to reconnect: {e.print_to_string()}");
error!("Failed to reconnect: {}", e.print_to_string());
}
}
}
@ -331,7 +327,7 @@ impl WebSocket {
Some(Ok(())) => {
self.model.borrow_mut().clear_callbacks();
self.model.borrow_mut().on_close_internal.set_callback(self.reconnect_trigger());
info!(self.logger, "Connection opened.");
info!("Connection opened.");
Ok(())
}
_ => Err(ConnectingError::FailedToConnect),
@ -398,14 +394,14 @@ impl WebSocket {
impl Transport for WebSocket {
fn send_text(&mut self, message: &str) -> Result<(), Error> {
info!(self.logger, "Sending text message of length {message.len()}.");
debug!(self.logger, "Message contents: {message}");
info!("Sending text message of length {}.", message.len());
debug!("Message contents: {message}");
self.send_with_open_socket(|ws| ws.send_with_str(message))
}
fn send_binary(&mut self, message: &[u8]) -> Result<(), Error> {
info!(self.logger, "Sending binary message of length {message.len()}.");
debug!(self.logger, || format!("Message contents: {:x?}", message));
info!("Sending binary message of length {}.", message.len());
debug!("Message contents: {:x?}", message);
// TODO [mwu]
// Here we workaround issue from wasm-bindgen 0.2.58:
// https://github.com/rustwasm/wasm-bindgen/issues/2014
@ -418,35 +414,32 @@ impl Transport for WebSocket {
}
fn set_event_transmitter(&mut self, transmitter: mpsc::UnboundedSender<TransportEvent>) {
info!(self.logger, "Setting event transmitter.");
info!("Setting event transmitter.");
let transmitter_copy = transmitter.clone();
let logger_copy = self.logger.clone_ref();
self.set_on_message(move |e| {
let data = e.data();
if let Some(text) = data.as_string() {
debug!(logger_copy, "Received a text message: {text}");
debug!("Received a text message: {text}");
channel::emit(&transmitter_copy, TransportEvent::TextMessage(text));
} else if let Ok(array_buffer) = data.dyn_into::<js_sys::ArrayBuffer>() {
let array = js_sys::Uint8Array::new(&array_buffer);
let binary_data = array.to_vec();
debug!(logger_copy, || format!("Received a binary message: {:x?}", binary_data));
debug!("Received a binary message: {:x?}", binary_data);
let event = TransportEvent::BinaryMessage(binary_data);
channel::emit(&transmitter_copy, event);
} else {
info!(logger_copy, "Received other kind of message: {e.data().print_to_string()}.");
info!("Received other kind of message: {}.", e.data().print_to_string());
}
});
let transmitter_copy = transmitter.clone();
let logger_copy = self.logger.clone_ref();
self.set_on_close(move |_e| {
info!(logger_copy, "Connection has been closed.");
info!("Connection has been closed.");
channel::emit(&transmitter_copy, TransportEvent::Closed);
});
let logger_copy = self.logger.clone_ref();
self.set_on_open(move |_e| {
info!(logger_copy, "Connection has been opened.");
info!("Connection has been opened.");
channel::emit(&transmitter, TransportEvent::Opened);
});
}
@ -469,16 +462,16 @@ mod tests {
async fn websocket_tests() {
executor::web::test::setup_and_forget();
let logger = DefaultTraceLogger::new("Test");
info!(logger, "Started");
info!("Started");
// Create WebSocket
let ws = WebSocket::new_opened(&logger, "ws://localhost:30445").await;
let mut ws = ws.expect("Couldn't connect to WebSocket server.");
info!(logger, "WebSocket opened: {ws:?}");
info!("WebSocket opened: {ws:?}");
// Log events
let handler = ws.establish_event_stream().for_each(f!([logger](event) {
info!(logger,"Socket emitted event: {event:?}");
let handler = ws.establish_event_stream().for_each(f!([](event) {
info!("Socket emitted event: {event:?}");
futures::future::ready(())
}));
@ -487,6 +480,6 @@ mod tests {
// Close socket after some delay.
web::sleep(Duration::from_secs(20)).await;
info!(logger, "Finished");
info!("Finished");
}
}

View File

@ -305,9 +305,8 @@ async fn file_events() {
/// * using project picker to open (or create) a project
/// * establishing a binary protocol connection with Language Server
async fn setup_ide() -> controller::Ide {
let logger = Logger::new("Test");
let config = enso_gui::config::Startup::default();
info!(logger, "Setting up the project.");
info!("Setting up the project.");
let initializer = enso_gui::Initializer::new(config);
let error_msg = "Couldn't open project.";
initializer.initialize_ide_controller().await.expect(error_msg)
@ -317,18 +316,17 @@ async fn setup_ide() -> controller::Ide {
#[allow(dead_code)]
/// This integration test covers writing and reading a file using the binary protocol
async fn file_operations_test() {
let logger = Logger::new("Test");
let _guard = enso_gui::initializer::setup_global_executor();
let ide = setup_ide().await;
let project = ide.current_project().expect("IDE is configured without an open project.");
info!(logger, "Got project: {project:?}");
info!("Got project: {project:?}");
// Edit file using the text protocol
let path = Path::new(project.json_rpc().project_root().id(), &["test_file.txt"]);
let contents = "Hello, 世界!".to_string();
let written = project.json_rpc().write_file(&path, &contents).await.unwrap();
info!(logger, "Written: {written:?}");
info!("Written: {written:?}");
let read_back = project.json_rpc().read_file(&path).await.unwrap();
info!(logger, "Read back: {read_back:?}");
info!("Read back: {read_back:?}");
assert_eq!(contents, read_back.contents);
// Edit file using the binary protocol.
@ -346,10 +344,9 @@ async fn file_operations_test() {
/// The future that tests attaching visualization and routing its updates.
async fn binary_visualization_updates_test_hlp() {
let logger = Logger::new("Test");
let ide = setup_ide().await;
let project = ide.current_project().expect("IDE is configured without an open project.");
info!(logger, "Got project: {project:?}");
info!("Got project: {project:?}");
use controller::project::MAIN_DEFINITION_NAME;
use ensogl::system::web::sleep;
@ -359,7 +356,7 @@ async fn binary_visualization_updates_test_hlp() {
let method = module_path.method_pointer(project.qualified_name(), MAIN_DEFINITION_NAME);
let module_qualified_name = project.qualified_module_name(&module_path);
let module = project.module(module_path).await.unwrap();
info!(logger, "Got module: {module:?}");
info!("Got module: {module:?}");
let graph_executed = controller::ExecutedGraph::new(&logger, project, method).await.unwrap();
let the_node = graph_executed.graph().nodes().unwrap()[0].info.clone();
@ -368,9 +365,9 @@ async fn binary_visualization_updates_test_hlp() {
// We must yield control for a moment, so the text edit is applied.
sleep(Duration::from_millis(1)).await;
info!(logger, "Main graph: {graph_executed:?}");
info!(logger, "The code is: {module.ast().repr():?}");
info!(logger, "Main node: {the_node:?} with {the_node.expression().repr()}");
info!("Main graph: {graph_executed:?}");
info!("The code is: {:?}", module.ast().repr());
info!("Main node: {the_node:?} with {}", the_node.expression().repr());
let method_pointer = QualifiedMethodPointer::module_method(
module_qualified_name,
@ -378,7 +375,7 @@ async fn binary_visualization_updates_test_hlp() {
);
let visualization = Visualization::new(the_node.id(), method_pointer, vec![]);
let stream = graph_executed.attach_visualization(visualization.clone()).await.unwrap();
info!(logger, "Attached the visualization {visualization.id}");
info!("Attached the visualization {}", visualization.id);
let mut stream = stream.boxed_local();
let first_event = stream.next().await.unwrap(); // await update
assert_eq!(first_event.as_ref(), "30".as_bytes());

View File

@ -118,7 +118,7 @@ enum State {
#[derive(Clone, Debug)]
pub struct EntryData {
display_object: display::object::Instance,
text: text::Area,
text: text::Text,
separator: separator::View,
ellipsis: ellipsis::View,
state: Rc<Cell<State>>,
@ -126,14 +126,13 @@ pub struct EntryData {
impl EntryData {
fn new(app: &Application, text_layer: Option<&Layer>) -> Self {
let logger = Logger::new("breadcrumbs::Entry");
let display_object = display::object::Instance::new(&logger);
let text = app.new_view::<ensogl_text::Area>();
let display_object = display::object::Instance::new();
let text = app.new_view::<ensogl_text::Text>();
if let Some(layer) = text_layer {
text.add_to_scene_layer(layer);
}
let ellipsis = ellipsis::View::new(&logger);
let separator = separator::View::new(&logger);
let ellipsis = ellipsis::View::new();
let separator = separator::View::new();
let state = default();
display_object.add_child(&ellipsis);
Self { display_object, state, text, ellipsis, separator }
@ -182,13 +181,13 @@ impl EntryData {
fn update_layout(&self, contour: Contour, text_size: text::Size, text_offset: f32) {
let size = contour.size;
self.text.set_position_xy(Vector2(text_offset - size.x / 2.0, text_size.raw / 2.0));
self.text.set_position_xy(Vector2(text_offset - size.x / 2.0, text_size.value / 2.0));
self.separator.size.set(size);
self.ellipsis.size.set(size);
}
fn set_default_color(&self, color: color::Rgba) {
self.text.set_default_color(color);
self.text.set_property_default(color);
self.ellipsis.alpha.set(color.alpha);
self.separator.color.set(color.into());
}
@ -198,7 +197,7 @@ impl EntryData {
}
fn set_default_text_size(&self, size: text::Size) {
self.text.set_default_text_size(size);
self.text.set_property_default(size);
}
fn is_state_change(&self, model: &Model) -> bool {

View File

@ -27,6 +27,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
@ -157,8 +158,8 @@ pub struct Model {
impl Model {
/// Constructor.
pub fn new(app: &Application) -> Self {
let display_object = display::object::Instance::new(&app.logger);
let mask = mask::View::new(&app.logger);
let display_object = display::object::Instance::new();
let mask = mask::View::new();
display_object.add_child(&mask);
let grid = GridView::new(app);
grid.reset_entries(1, 0);
@ -213,7 +214,7 @@ impl Model {
text_padding_left: *text_padding,
text_size: text::Size::from(*text_size),
hover_color:*hover_color,
font_name: ImString::new(font),
font_name: font.clone(),
selected_color: *selected_color,
highlight_corners_radius,
greyed_out_color: *greyed_out_color,

View File

@ -174,7 +174,7 @@ impl View {
let mut icon = icon.borrow_mut();
if !icon.id.contains(&model.icon) {
icon.id = Some(model.icon);
let shape = model.icon.create_shape(&self.logger, Vector2(icon::SIZE, icon::SIZE));
let shape = model.icon.create_shape(Vector2(icon::SIZE, icon::SIZE));
shape.strong_color.set(strong_color.into());
shape.weak_color.set(weak_color.into());
shape.set_position_x(icon::SIZE / 2.0);
@ -197,7 +197,7 @@ impl list_view::Entry for View {
Params { colors, selection_layer }: &Params,
) -> Self {
let logger = Logger::new("component_group::Entry");
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
let icon: Rc<RefCell<CurrentIcon>> = default();
let selected_icon: Rc<RefCell<CurrentIcon>> = default();
let label = GlyphHighlightedLabel::new(app, style_prefix, &());
@ -209,7 +209,7 @@ impl list_view::Entry for View {
selected_label.set_label_layer(&layer);
display_object.add_child(&selected_label);
} else {
error!(logger, "Selection layer is dropped.");
error!("Selection layer is dropped.");
}
}
@ -231,8 +231,8 @@ impl list_view::Entry for View {
label.set_max_width(*width);
selected_label.set_max_width(*width);
});
label.inner.label.set_default_color <+ all(&colors.entry_text, &init)._0();
selected_label.inner.label.set_default_color <+ all(&colors.selected.entry_text,&init)._0();
label.inner.label.set_property_default <+ all(&colors.entry_text, &init)._0().ref_into_some();
selected_label.inner.label.set_property_default <+ all(&colors.selected.entry_text,&init)._0().ref_into_some();
eval colors.icon_strong ((&c) icon.borrow().set_strong_color(c));
eval colors.selected.icon_strong((&c) selected_icon.borrow().set_strong_color(c));
eval colors.icon_weak ((&c) icon.borrow().set_weak_color(c));
@ -275,7 +275,7 @@ impl list_view::Entry for View {
self.colors.selected.icon_weak.value(),
);
} else {
error!(self.logger, "Cannot add icon shape to a dropped scene layer.");
error!("Cannot add icon shape to a dropped scene layer.");
}
}
}

View File

@ -44,11 +44,10 @@
///
/// fn main () {
/// let app = ensogl::application::Application::new("root");
/// let logger = Logger::new("icon");
/// let icon1 = Id::Icon1.create_shape(&logger, Vector2(10.0, 10.0));
/// let icon1 = Id::Icon1.create_shape(Vector2(10.0, 10.0));
/// let icon2_id: Id = "Icon2".parse().unwrap();
/// assert_eq!(icon2_id, Id::Icon2);
/// let icon2 = icon2_id.create_shape(&logger, Vector2(11.0, 11.0));
/// let icon2 = icon2_id.create_shape(Vector2(11.0, 11.0));
/// app.display.default_scene.add_child(&icon1);
/// app.display.default_scene.add_child(&icon2);
///
@ -81,10 +80,10 @@ macro_rules! define_icons {
impl Id {
/// Create icon's shape with given size.
pub fn create_shape(&self, logger: impl AnyLogger, size: Vector2) -> $crate::icon::Any {
pub fn create_shape(&self, size: Vector2) -> $crate::icon::Any {
match self {$(
Self::$variant => {
let view = $name::View::new(logger);
let view = $name::View::new();
view.size.set(size);
let strong_color = view.strong_color.clone_ref();
let weak_color = view.weak_color.clone_ref();

View File

@ -41,7 +41,7 @@ impl list_view::Entry for Entry {
fn new(app: &Application, _style_prefix: &Path, params: &Self::Params) -> Self {
let logger = app.logger.sub("NavigatorIcon");
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
let icon: Rc<RefCell<Option<icon::Any>>> = default();
let icon_id = default();
let network = frp::Network::new("searcher_list_panel::navigator::Icon");
@ -60,7 +60,7 @@ impl list_view::Entry for Entry {
fn update(&self, model: &Self::Model) {
if !self.icon_id.get().contains(model) {
let size = Vector2(icon::SIZE, icon::SIZE);
let icon = model.create_shape(&self.logger, size);
let icon = model.create_shape(size);
icon.strong_color.set(self.params.strong_color.value().into());
icon.weak_color.set(self.params.weak_color.value().into());
self.display_object.add_child(&icon);

View File

@ -47,6 +47,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
@ -411,8 +412,13 @@ ensogl::define_endpoints_2! {
}
impl component::Frp<Model> for Frp {
fn init(api: &Self::Private, app: &Application, model: &Model, style: &StyleWatchFrp) {
let network = &api.network;
fn init(
network: &frp::Network,
api: &Self::Private,
app: &Application,
model: &Model,
style: &StyleWatchFrp,
) {
let mouse_position = app.display.default_scene.mouse.frp.position.clone_ref();
let input = &api.input;
let out = &api.output;
@ -461,16 +467,16 @@ impl component::Frp<Model> for Frp {
model.header.set_font <+ header_text_font;
model.selected_header.set_font <+ header_text_font;
header_text_size <- all(&header_text_size, &init)._0();
model.header.set_default_text_size <+ header_text_size.map(|v| text::Size(*v));
model.selected_header.set_default_text_size <+ header_text_size.map(|v| text::Size(*v));
model.header.set_property_default <+ header_text_size.map(|v| text::Size(*v)).ref_into_some();
model.selected_header.set_property_default <+ header_text_size.map(|v| text::Size(*v)).ref_into_some();
_set_header <- input.set_header.map2(&size_and_header_geometry, f!(
(text, (size, hdr_geom, _)) {
model.header_text.replace(text.clone());
model.update_header_width(*size, *hdr_geom);
})
);
model.header.set_default_color <+ colors.header_text;
model.selected_header.set_default_color <+ all(&colors.selected.header_text,&init)._0();
model.header.set_property_default <+ colors.header_text.ref_into_some();
model.selected_header.set_property_default <+ all(&colors.selected.header_text,&init)._0().ref_into_some();
eval colors.background((c) model.background.color.set(c.into()));
eval colors.background((c) model.header_background.color.set(c.into()));
eval colors.selected.background((c) model.selection_background.color.set(c.into()));
@ -639,12 +645,12 @@ impl LayersInner {
pub struct Model {
display_object: display::object::Instance,
entries: list_view::ListView<Entry>,
header: text::Area,
header: text::Text,
header_background: header_background::View,
header_text: Rc<RefCell<String>>,
header_overlay: header_overlay::View,
background: background::View,
selected_header: text::Area,
selected_header: text::Text,
selection_header_background: selection_header_background::View,
selection_background: background::View,
}
@ -660,16 +666,16 @@ impl component::Model for Model {
"ComponentGroup"
}
fn new(app: &Application, logger: &Logger) -> Self {
fn new(app: &Application) -> Self {
let header_text = default();
let display_object = display::object::Instance::new(&logger);
let header_overlay = header_overlay::View::new(&logger);
let background = background::View::new(&logger);
let selection_background = background::View::new(&logger);
let header_background = header_background::View::new(&logger);
let selection_header_background = selection_header_background::View::new(&logger);
let header = text::Area::new(app);
let selected_header = text::Area::new(app);
let display_object = display::object::Instance::new();
let header_overlay = header_overlay::View::new();
let background = background::View::new();
let selection_background = background::View::new();
let header_background = header_background::View::new();
let selection_header_background = selection_header_background::View::new();
let header = text::Text::new(app);
let selected_header = text::Text::new(app);
let entries = app.new_view::<list_view::ListView<Entry>>();
entries.set_style_prefix(entry::STYLE_PATH);
entries.set_background_color(HOVER_COLOR);
@ -785,9 +791,8 @@ impl Model {
let header_padding_left = header_geometry.padding_left;
let header_padding_right = header_geometry.padding_right;
let max_text_width = size.x - header_padding_left - header_padding_right;
let header_text = self.header_text.borrow().clone();
self.header.set_content_truncated(header_text.clone(), max_text_width);
self.selected_header.set_content_truncated(header_text, max_text_width);
self.header.set_view_width(max_text_width);
self.selected_header.set_view_width(max_text_width);
}
fn selection_position(

View File

@ -113,7 +113,7 @@ pub struct Model {
pub kind: Kind,
pub color: color::Rgba,
pub caption: ImString,
pub highlighted: Rc<Vec<text::Range<text::Bytes>>>,
pub highlighted: Rc<Vec<text::Range<text::Byte>>>,
pub icon: Option<icon::Id>,
pub group_id: GroupId,
}
@ -179,9 +179,7 @@ struct CurrentIcon {
impl Default for CurrentIcon {
fn default() -> Self {
Self {
display_object: display::object::Instance::new(Logger::new(
"component_browser_entry_icon",
)),
display_object: display::object::Instance::new(),
strong_color: default(),
weak_color: default(),
shape: default(),
@ -195,10 +193,7 @@ impl CurrentIcon {
if self.id != new_icon {
self.id = new_icon;
if let Some(icon_id) = new_icon {
let shape = icon_id.create_shape(
Logger::new("ComponentBrowserEntry"),
Vector2(icon::SIZE, icon::SIZE),
);
let shape = icon_id.create_shape(Vector2(icon::SIZE, icon::SIZE));
tracing::debug!("Creating new icon {icon_id:?}.");
shape.strong_color.set(self.strong_color.into());
shape.weak_color.set(self.weak_color.into());
@ -238,7 +233,7 @@ impl display::Object for CurrentIcon {
#[derive(Clone, CloneRef, Debug)]
pub struct Data {
display_object: display::object::Instance,
label: text::Area,
label: text::Text,
background: background::View,
icon: Rc<RefCell<CurrentIcon>>,
style: StyleWatchFrp,
@ -246,14 +241,15 @@ pub struct Data {
impl Data {
fn new(app: &Application, text_layer: Option<&Layer>) -> Self {
let display_object = display::object::Instance::new(Logger::new("ComponentGroupEntry"));
let label = app.new_view::<text::Area>();
let background = background::View::new(Logger::new("ComponentGroupEntry"));
let display_object = display::object::Instance::new();
let label = app.new_view::<text::Text>();
let background = background::View::new();
let icon = CurrentIcon::default();
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet);
display_object.add_child(&background);
display_object.add_child(&icon);
display_object.add_child(&label);
label.set_long_text_truncation_mode(true);
if let Some(layer) = text_layer {
label.add_to_scene_layer(layer);
}
@ -280,7 +276,7 @@ impl Data {
let left = -entry_size.x / 2.0 + style.padding;
self.icon.borrow().set_position_x(left + style.icon_size / 2.0);
let text_x = Self::text_x_position(kind, style);
self.label.set_position_xy(Vector2(text_x, style.text_size.raw / 2.0));
self.label.set_position_xy(Vector2(text_x, style.text_size.value / 2.0));
}
fn contour(kind: Kind, style: &Style, entry_size: Vector2) -> Contour {
@ -401,7 +397,7 @@ impl grid_view::Entry for View {
});
let colors = Colors::from_main_color(network, &data.style, &color, &style, &is_dimmed);
eval colors.background ((c) data.background.color.set(c.into()));
data.label.set_default_color <+ colors.text;
data.label.set_property_default <+ colors.text.ref_into_some();
eval colors.icon_strong ((c) data.icon.borrow_mut().set_strong_color(*c));
eval colors.icon_weak ((c) data.icon.borrow_mut().set_weak_color(*c));
out.hover_highlight_color <+ colors.hover_highlight;
@ -416,9 +412,10 @@ impl grid_view::Entry for View {
// === Icon and Text ===
max_text_width <- kind_and_style.map(|(kind, style)| Data::max_text_width(*kind, style));
caption <- input.set_model.map(|m| m.caption.to_string());
caption <- input.set_model.map(|m| m.caption.clone_ref());
icon <- input.set_model.map(|m| m.icon);
data.label.set_content_truncated <+ all(caption, max_text_width);
data.label.set_content <+ caption;
data.label.set_view_width <+ max_text_width.some();
content_changed <- data.label.content.constant(());
style_changed <- style.constant(());
highlight_range <= all_with3(
@ -427,12 +424,12 @@ impl grid_view::Entry for View {
&style_changed,
|m, (), ()| m.highlighted.deref().clone()
);
data.label.set_sdf_bold <+ highlight_range.map2(&style, |range, s| {
(*range, text::style::SdfBold::new(s.highlight_bold))
data.label.set_property <+ highlight_range.map2(&style, |range, s| {
(range.into(), Some(text::SdfWeight::new(s.highlight_bold).into()))
});
data.label.set_default_text_size <+ style.map(|s| s.text_size);
data.label.set_property_default <+ style.map(|s| s.text_size).ref_into_some();
eval icon ((&icon) data.icon.borrow_mut().update(icon));
data.label.set_font <+ style.map(|s| s.font.to_string()).on_change();
data.label.set_font <+ style.map(|s| s.font.clone_ref()).on_change();
}
Self { frp, data }
}

View File

@ -134,12 +134,12 @@ ensogl::define_endpoints_2! {
impl<const COLUMNS: usize> component::Frp<Model<COLUMNS>> for Frp {
fn init(
network: &frp::Network,
api: &Self::Private,
_app: &Application,
model: &Model<COLUMNS>,
style: &StyleWatchFrp,
) {
let network = &api.network;
let input = &api.input;
let out = &api.output;
let colors = Colors::from_main_color(network, style, &input.set_color, &input.set_dimmed);
@ -378,11 +378,11 @@ impl<const COLUMNS: usize> component::Model for Model<COLUMNS> {
"WideComponentGroupView"
}
fn new(app: &Application, logger: &Logger) -> Self {
let display_object = display::object::Instance::new(&logger);
let background = background::View::new(&logger);
fn new(app: &Application) -> Self {
let display_object = display::object::Instance::new();
let background = background::View::new();
display_object.add_child(&background);
let selection_background = background::View::new(&logger);
let selection_background = background::View::new();
display_object.add_child(&selection_background);
let columns: Vec<_> = (0..COLUMNS).map(|i| Column::new(app, ColumnId::new(i))).collect();
let columns = Rc::new(columns);

View File

@ -69,9 +69,8 @@ pub struct Model {
impl Model {
fn new(app: &Application) -> Self {
let logger = Logger::new("ColumnGrid");
let app = app.clone_ref();
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
Self { app, display_object, content: default(), size: default(), layers: default() }
}
@ -207,7 +206,7 @@ impl component::Model for Model {
"ColumnGrid"
}
fn new(app: &Application, _logger: &DefaultWarningLogger) -> Self {
fn new(app: &Application) -> Self {
Self::new(app)
}
}
@ -295,12 +294,12 @@ fn get_layout(
impl component::Frp<Model> for Frp {
fn init(
network: &frp::Network,
frp_api: &<Self as API>::Private,
_app: &Application,
model: &Model,
style: &StyleWatchFrp,
) {
let network = &frp_api.network;
let input = &frp_api.input;
let (layout_update, init) = get_layout(network, style);

View File

@ -8,7 +8,6 @@
#![recursion_limit = "512"]
// === Features ===
#![allow(incomplete_features)]
#![feature(negative_impls)]
#![feature(associated_type_defaults)]
#![feature(bool_to_option)]
#![feature(cell_update)]
@ -31,6 +30,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![allow(clippy::option_map_unit_fn)]
#![allow(clippy::precedence)]
@ -184,7 +184,7 @@ struct Style {
section_heading_size: f32,
section_heading_offset: f32,
section_heading_text_offset: f32,
section_heading_font: String,
section_heading_font: ImString,
section_heading_color: color::Rgba,
section_divider_color: color::Rgba,
@ -431,13 +431,13 @@ impl Model {
fn new(app: &Application) -> Self {
let logger = Logger::new("ComponentBrowserPanel");
let app = app.clone_ref();
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
let navigator = default();
let groups_wrapper = component_group::set::Wrapper::new();
let background = background::View::new(&logger);
let background = background::View::new();
display_object.add_child(&background);
let navigator_shadow = navigator_shadow::View::new(&logger);
let navigator_shadow = navigator_shadow::View::new();
display_object.add_child(&navigator_shadow);
let favourites_section = Self::init_column_section(&app);
@ -465,7 +465,7 @@ impl Model {
display_object.add_child(&breadcrumbs);
breadcrumbs.show_ellipsis(true);
let selection = selection_box::View::new(&app.logger);
let selection = selection_box::View::new();
scroll_area.add_child(&selection);
layers.selection_mask.add_exclusive(&selection);
@ -702,7 +702,7 @@ impl component::Model for Model {
"ComponentBrowserPanel"
}
fn new(app: &Application, _logger: &DefaultWarningLogger) -> Self {
fn new(app: &Application) -> Self {
Self::new(app)
}
}
@ -717,7 +717,7 @@ impl component::Model for Model {
/// provides some utility functions for shape and layout handling.
#[derive(Clone, Debug)]
struct LabeledSection<T> {
pub label: text::Area,
pub label: text::Text,
pub divider: hline::View,
pub content: T,
}
@ -737,16 +737,15 @@ type ColumnSection = LabeledSection<column_grid::ColumnGrid>;
impl<T: CloneRef> LabeledSection<T> {
pub fn new(content: T, app: &Application) -> Self {
let logger = Logger::new("LabeledSection");
let label = text::Area::new(app);
let divider = hline::View::new(logger);
let label = text::Text::new(app);
let divider = hline::View::new();
Self { label, divider, content }
}
fn set_style(&self, style: &Style) {
self.divider.size.set(Vector2(INFINITE, style.section_divider_height));
self.label.set_default_color(style.section_heading_color);
self.label.set_default_text_size(text::Size(style.section_heading_size));
self.label.set_property_default(style.section_heading_color);
self.label.set_property_default(text::Size(style.section_heading_size));
self.label.set_font(style.section_heading_font.clone());
self.label.set_position_x(style.content_padding);
}
@ -963,12 +962,12 @@ define_endpoints_2! {
impl component::Frp<Model> for Frp {
fn init(
network: &frp::Network,
frp_api: &<Self as API>::Private,
app: &Application,
model: &Model,
style: &StyleWatchFrp,
) {
let network = &frp_api.network;
let header_height = style.get_number(component_group_theme::header::height);
let layout_frp = Style::from_theme(network, style);
let scene = &app.display.default_scene;

View File

@ -92,7 +92,7 @@ const BOTTOM_BUTTONS: [icon::Id; 3] = [icon::Id::SubModules, icon::Id::LocalScop
impl Navigator {
pub fn new(app: &Application) -> Self {
let display_object = display::object::Instance::new(&app.logger);
let display_object = display::object::Instance::new();
let top_buttons = app.new_view::<list_view::ListView<icon::Entry>>();
let bottom_buttons = app.new_view::<list_view::ListView<icon::Entry>>();
top_buttons.set_style_prefix(list_panel_theme::navigator_list_view::HERE.str);

View File

@ -7,6 +7,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]

View File

@ -3,6 +3,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
@ -16,7 +17,7 @@ use ensogl_core::display::shape::*;
use ensogl_core::prelude::*;
use wasm_bindgen::prelude::*;
use enso_text::Bytes;
use enso_text::Byte;
use ensogl_core::application::Application;
use ensogl_core::data::color;
use ensogl_core::display::object::ObjectOps;
@ -90,7 +91,7 @@ struct MockEntries {
impl MockEntries {
fn new(count: usize) -> Rc<Self> {
const HIGHLIGHTED_ENTRY_NAME: &str = "convert";
const HIGHLIGHTED_RANGE: Range<Bytes> = Bytes(0)..Bytes(3);
const HIGHLIGHTED_RANGE: Range<Byte> = Byte(0)..Byte(3);
Rc::new(Self {
entries: PREPARED_ITEMS
.iter()
@ -284,7 +285,7 @@ fn init(app: &Application) {
// FIXME(#182193824): This is a workaround for a bug. See the docs of the
// [`transparent_circle`].
{
let transparent_circle = transparent_circle::View::new(&app.logger);
let transparent_circle = transparent_circle::View::new();
transparent_circle.size.set(Vector2(150.0, 150.0));
transparent_circle.set_position_xy(Vector2(200.0, -150.0));
scroll_area.content().add_child(&transparent_circle);

View File

@ -3,7 +3,6 @@
#![recursion_limit = "512"]
// === Features ===
#![allow(incomplete_features)]
#![feature(negative_impls)]
#![feature(associated_type_defaults)]
#![feature(bool_to_option)]
#![feature(cell_update)]
@ -22,6 +21,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![allow(clippy::option_map_unit_fn)]
#![allow(clippy::precedence)]

View File

@ -1,6 +1,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
use ensogl::system::web::traits::*;
use ide_view_component_group::prelude::*;
@ -45,7 +46,6 @@ mod frame {
#[wasm_bindgen]
#[allow(dead_code)]
pub fn entry_point_searcher_icons() {
let logger = Logger::new("Icons example");
let app = Application::new("root");
ensogl_hardcoded_theme::builtin::dark::register(&app);
ensogl_hardcoded_theme::builtin::light::register(&app);
@ -79,7 +79,7 @@ pub fn entry_point_searcher_icons() {
let mut x = -300.0;
icon::Id::for_each(|id| {
let shape = id.create_shape(&logger, Vector2(icon::SIZE, icon::SIZE));
let shape = id.create_shape(Vector2(icon::SIZE, icon::SIZE));
shape.strong_color.set(color::Rgba(0.243, 0.541, 0.160, 1.0).into());
shape.weak_color.set(color::Rgba(0.655, 0.788, 0.624, 1.0).into());
shape.set_position_x(x);

View File

@ -5,6 +5,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
@ -107,7 +108,7 @@ fn init(app: &Application) {
app.views.register::<root::View>();
app.views.register::<project::View>();
app.views.register::<text::Area>();
app.views.register::<text::Text>();
app.views.register::<GraphEditor>();
let root_view = app.new_view::<root::View>();
let project_view = root_view.project();

View File

@ -22,6 +22,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![allow(clippy::option_map_unit_fn)]
#![allow(clippy::precedence)]
@ -128,7 +129,7 @@ impl EntryModelProvider {
}
};
let highlighted = if row == 4 {
vec![text::Range::new(text::Bytes(2), text::Bytes(4))]
vec![text::Range::new(text::Byte(2), text::Byte(4))]
} else {
vec![]
};

View File

@ -6,6 +6,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]

View File

@ -3,6 +3,7 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]

View File

@ -66,7 +66,7 @@ impl BubbleChartModel {
// Avoid re-creating views, if we have already created some before.
let mut views = self.views.borrow_mut();
views.resize_with(data_inner.len(), || shape::View::new(&self.logger));
views.resize_with(data_inner.len(), shape::View::new);
// TODO[mm] this is somewhat inefficient, as the canvas for each bubble is too large.
// But this ensures that we can get a cropped view area and avoids an issue with the data
@ -106,7 +106,7 @@ impl BubbleChart {
pub fn new(scene: &Scene) -> Self {
let logger = Logger::new("bubble");
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
let views = Rc::new(RefCell::new(vec![]));
let network = frp::Network::new("bubble_chart");
let frp = visualization::instance::Frp::new(&network);

View File

@ -194,15 +194,15 @@ impl BreadcrumbsModel {
let scene = &app.display.default_scene;
let project_name = app.new_view();
let logger = Logger::new("Breadcrumbs");
let display_object = display::object::Instance::new(&logger);
let root = display::object::Instance::new(&logger);
let breadcrumbs_container = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
let root = display::object::Instance::new();
let breadcrumbs_container = display::object::Instance::new();
let scene = scene.clone_ref();
let breadcrumbs = default();
let frp_inputs = frp.input.clone_ref();
let current_index = default();
let camera = scene.camera().clone_ref();
let background = background::View::new(&logger);
let background = background::View::new();
let gap_width = default();
scene.layers.panel.add_exclusive(&background);
@ -288,7 +288,7 @@ impl BreadcrumbsModel {
/// where `popped_count` is the number of breadcrumbs in the right side of `index` that needs to
/// be popped or a list of `LocalCall`s identifying the breadcrumbs we need to push.
fn select_breadcrumb(&self, index: usize) -> (usize, Vec<Option<LocalCall>>) {
debug!(self.logger, "Selecting breadcrumb #{index}.");
debug!("Selecting breadcrumb #{index}.");
let current_index = self.current_index.get();
match index.cmp(&current_index) {
Ordering::Less => (current_index - index, default()),
@ -310,7 +310,7 @@ impl BreadcrumbsModel {
if info.is_some() {
local_calls.push(info);
} else {
error!(self.logger, "LocalCall info is not present.");
error!("LocalCall info is not present.");
self.remove_breadcrumbs_history_beginning_from(index);
break;
}
@ -336,9 +336,9 @@ impl BreadcrumbsModel {
.contains_if(|breadcrumb| breadcrumb.info.expression_id == *expression_id);
if breadcrumb_exists {
debug!(self.logger, "Entering an existing {method_pointer.name} breadcrumb.");
debug!("Entering an existing {} breadcrumb.", method_pointer.name);
} else {
debug!(self.logger, "Creating a new {method_pointer.name} breadcrumb.");
debug!("Creating a new {} breadcrumb.", method_pointer.name);
self.remove_breadcrumbs_history_beginning_from(self.current_index.get());
let breadcrumb = Breadcrumb::new(&self.app, method_pointer, expression_id);
let network = &breadcrumb.frp.network;
@ -351,7 +351,7 @@ impl BreadcrumbsModel {
);
}
debug!(self.logger, "Pushing {breadcrumb.info.method_pointer.name} breadcrumb.");
debug!("Pushing {} breadcrumb.", breadcrumb.info.method_pointer.name);
breadcrumb.set_position_x(self.breadcrumbs_container_width().round());
self.breadcrumbs_container.add_child(&breadcrumb);
self.breadcrumbs.borrow_mut().push(breadcrumb);
@ -413,9 +413,9 @@ impl BreadcrumbsModel {
/// Pops a breadcrumb and returns the index of the previously selected breadcrumb, and the
/// index of the newly selected one in the form of (old,new).
fn pop_breadcrumb(&self) -> Option<(usize, usize)> {
debug!(self.logger, "Popping {self.current_index.get()}");
debug!("Popping {}", self.current_index.get());
(self.current_index.get() > 0).as_option().map(|_| {
debug!(self.logger, "Popping breadcrumb view.");
debug!("Popping breadcrumb view.");
let old_index = self.current_index.get();
let new_index = old_index - 1;
self.current_index.set(new_index);
@ -426,7 +426,7 @@ impl BreadcrumbsModel {
fn remove_breadcrumbs_history_beginning_from(&self, index: usize) {
for breadcrumb in self.breadcrumbs.borrow_mut().split_off(index) {
debug!(self.logger, "Removing {breadcrumb.info.method_pointer.name}.");
debug!("Removing {}.", breadcrumb.info.method_pointer.name);
breadcrumb.unset_parent();
}
self.update_layout();

View File

@ -259,12 +259,11 @@ pub struct BreadcrumbInfo {
/// Breadcrumbs model.
#[derive(Debug, Clone, CloneRef)]
pub struct BreadcrumbModel {
logger: Logger,
display_object: display::object::Instance,
view: background::View,
separator: separator::View,
icon: icon::View,
label: text::Area,
label: text::Text,
animations: Animations,
style: StyleWatch,
/// Breadcrumb information such as name and expression id.
@ -283,13 +282,11 @@ impl BreadcrumbModel {
expression_id: &ast::Id,
) -> Self {
let scene = &app.display.default_scene;
let logger = Logger::new("Breadcrumbs");
let display_object = display::object::Instance::new(&logger);
let view_logger = Logger::new_sub(&logger, "view_logger");
let view = background::View::new(&view_logger);
let icon = icon::View::new(&view_logger);
let separator = separator::View::new(&view_logger);
let label = app.new_view::<text::Area>();
let display_object = display::object::Instance::new();
let view = background::View::new();
let icon = icon::View::new();
let separator = separator::View::new();
let label = app.new_view::<text::Text>();
let expression_id = *expression_id;
let method_pointer = method_pointer.clone();
let info = Rc::new(BreadcrumbInfo { method_pointer, expression_id });
@ -323,7 +320,6 @@ impl BreadcrumbModel {
// system (#795)
let style = StyleWatch::new(&scene.style_sheet);
Self {
logger,
display_object,
view,
separator,
@ -350,9 +346,9 @@ impl BreadcrumbModel {
let color = if self.is_selected() { full_color } else { transparent_color };
self.label.set_default_color.emit(color);
self.label.set_default_text_size(text::style::Size::from(TEXT_SIZE));
self.label.single_line(true);
self.label.set_property_default(color);
self.label.set_property_default(text::formatting::Size::from(TEXT_SIZE));
self.label.set_single_line_mode(true);
self.label.set_position_x(ICON_RADIUS + ICON_RIGHT_MARGIN);
self.label.set_position_y(TEXT_SIZE / 2.0);
self.label.set_content(&self.info.method_pointer.name);
@ -403,7 +399,7 @@ impl BreadcrumbModel {
fn set_color(&self, value: Vector4<f32>) {
let color = color::Rgba::from(value);
self.label.set_color_all(color);
self.label.set_property(.., color);
self.icon.red.set(color.red);
self.icon.green.set(color.green);
self.icon.blue.set(color.blue);

View File

@ -9,7 +9,6 @@ use crate::component::breadcrumbs::TEXT_SIZE;
use crate::component::breadcrumbs::VERTICAL_MARGIN;
use enso_frp as frp;
use ensogl::application;
use ensogl::application::shortcut;
use ensogl::application::Application;
use ensogl::data::color;
@ -18,9 +17,8 @@ use ensogl::display::object::ObjectOps;
use ensogl::gui::cursor;
use ensogl::DEPRECATED_Animation;
use ensogl_component::text;
use ensogl_component::text::style::Size as TextSize;
use ensogl_component::text::formatting::Size as TextSize;
use ensogl_hardcoded_theme as theme;
use logger::DefaultWarningLogger as Logger;
@ -122,11 +120,10 @@ impl Animations {
#[allow(missing_docs)]
struct ProjectNameModel {
app: Application,
logger: Logger,
display_object: display::object::Instance,
view: background::View,
style: StyleWatch,
text_field: text::Area,
text_field: text::Text,
project_name: Rc<RefCell<String>>,
}
@ -135,29 +132,27 @@ impl ProjectNameModel {
fn new(app: &Application) -> Self {
let app = app.clone_ref();
let scene = &app.display.default_scene;
let logger = Logger::new("ProjectName");
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
// FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape
// system (#795)
let style = StyleWatch::new(&scene.style_sheet);
let base_color = style.get_color(theme::graph_editor::breadcrumbs::transparent);
let text_size: TextSize = TEXT_SIZE.into();
let text_field = app.new_view::<text::Area>();
text_field.set_default_color.emit(base_color);
text_field.set_default_text_size(text_size);
text_field.single_line(true);
let text_field = app.new_view::<text::Text>();
text_field.set_property_default(base_color);
text_field.set_property_default(text_size);
text_field.set_single_line_mode(true);
text_field.remove_from_scene_layer(&scene.layers.main);
text_field.add_to_scene_layer(&scene.layers.panel_text);
text_field.hover();
let view_logger = Logger::new_sub(&logger, "view_logger");
let view = background::View::new(&view_logger);
let view = background::View::new();
scene.layers.panel.add_exclusive(&view);
let project_name = default();
Self { app, logger, display_object, view, style, text_field, project_name }.init()
Self { app, display_object, view, style, text_field, project_name }.init()
}
/// Compute the width of the ProjectName view.
@ -190,7 +185,7 @@ impl ProjectNameModel {
/// Revert the text field content to the last committed project name.
fn reset_name(&self) {
debug!(self.logger, "Resetting project name.");
debug!("Resetting project name.");
self.update_text_field_content(self.project_name.borrow().as_str());
}
@ -201,7 +196,7 @@ impl ProjectNameModel {
}
fn set_color(&self, value: color::Rgba) {
self.text_field.set_default_color(value);
self.text_field.set_property_default(value);
}
fn set_position(&self, value: Vector3<f32>) {
@ -211,7 +206,7 @@ impl ProjectNameModel {
/// Change the text field content and commit the given name.
fn rename(&self, name: impl Str) {
let name = name.into();
debug!(self.logger, "Renaming: '{name}'.");
debug!("Renaming: '{name}'.");
self.update_text_field_content(&name);
self.commit(name);
}
@ -219,7 +214,7 @@ impl ProjectNameModel {
/// Confirm the given name as the current project name.
fn commit<T: Into<String>>(&self, name: T) {
let name = name.into();
debug!(self.logger, "Committing name: '{name}'.");
debug!("Committing name: '{name}'.");
*self.project_name.borrow_mut() = name;
}
}
@ -341,14 +336,14 @@ impl ProjectName {
on_mouse_over_and_editable <- all(frp.output.is_hovered,editable).map(|(a,b)| *a && *b);
mouse_over_while_editing <- on_mouse_over_and_editable.gate(&on_mouse_over_and_editable);
frp.output.source.pointer_style <+ mouse_over_while_editing.map(|_|
cursor::Style::new_text_cursor()
cursor::Style::cursor()
);
no_mouse_or_edit <- on_mouse_over_and_editable.gate_not(&on_mouse_over_and_editable);
frp.output.source.pointer_style <+ no_mouse_or_edit.map(|_|
cursor::Style::default()
);
frp.output.source.pointer_style <+ frp.input.start_editing.gate(&frp.output.is_hovered).map(|_|
cursor::Style::new_text_cursor()
cursor::Style::cursor()
);
}
@ -372,7 +367,7 @@ impl Deref for ProjectName {
}
}
impl application::command::FrpNetworkProvider for ProjectName {
impl FrpNetworkProvider for ProjectName {
fn network(&self) -> &frp::Network {
&self.frp.network
}

View File

@ -762,8 +762,8 @@ macro_rules! define_components {
/// Constructor.
#[allow(clippy::vec_init_then_push)]
pub fn new(logger:Logger) -> Self {
let display_object = display::object::Instance::new(&logger);
$(let $field = <$field_type>::new(Logger::new_sub(&logger,stringify!($field)));)*
let display_object = display::object::Instance::new();
$(let $field = <$field_type>::new();)*
$(display_object.add_child(&$field);)*
let mut shape_view_events:Vec<PointerTarget> = Vec::default();
$(shape_view_events.push($field.events.clone_ref());)*
@ -1283,10 +1283,10 @@ impl EdgeModelData {
#[profile(Debug)]
pub fn new(scene: &Scene, network: &frp::Network) -> Self {
let logger = Logger::new("edge");
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
let front = Front::new(Logger::new_sub(&logger, "front"));
let back = Back::new(Logger::new_sub(&logger, "back"));
let joint = joint::View::new(Logger::new_sub(&logger, "joint"));
let joint = joint::View::new();
display_object.add_child(&front);
display_object.add_child(&back);

View File

@ -25,7 +25,6 @@ use ensogl::gui;
use ensogl::Animation;
use ensogl_component::shadow;
use ensogl_component::text;
use ensogl_component::text::Text;
use ensogl_hardcoded_theme as theme;
use ensogl_hardcoded_theme;
use std::f32::EPSILON;
@ -95,7 +94,7 @@ const UNRESOLVED_SYMBOL_TYPE: &str = "Builtins.Main.Unresolved_Symbol";
///
/// This is just a plain string, as this is what text area expects and node just redirects this
/// value,
pub type Comment = String;
pub type Comment = ImString;
@ -324,7 +323,7 @@ ensogl::define_endpoints_2! {
/// Press event. Emitted when user clicks on non-active part of the node, like its
/// background. In edit mode, the whole node area is considered non-active.
background_press (),
expression (Text),
expression (enso_text::Rope),
comment (Comment),
skip (bool),
freeze (bool),
@ -447,7 +446,7 @@ pub struct NodeModel {
pub action_bar: action_bar::ActionBar,
pub vcs_indicator: vcs::StatusIndicator,
pub style: StyleWatchFrp,
pub comment: text::Area,
pub comment: text::Text,
}
impl NodeModel {
@ -481,17 +480,13 @@ impl NodeModel {
let scene = &app.display.default_scene;
let logger = Logger::new("node");
let main_logger = Logger::new_sub(&logger, "main_area");
let drag_logger = Logger::new_sub(&logger, "drag_area");
let error_indicator_logger = Logger::new_sub(&logger, "error_indicator");
let error_indicator = error_shape::View::new(&error_indicator_logger);
let error_indicator = error_shape::View::new();
let profiling_label = ProfilingLabel::new(app);
let backdrop = backdrop::View::new(&main_logger);
let background = background::View::new(&main_logger);
let drag_area = drag_area::View::new(&drag_logger);
let backdrop = backdrop::View::new();
let background = background::View::new();
let drag_area = drag_area::View::new();
let vcs_indicator = vcs::StatusIndicator::new(app);
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
display_object.add_child(&profiling_label);
display_object.add_child(&drag_area);
@ -499,7 +494,7 @@ impl NodeModel {
display_object.add_child(&background);
display_object.add_child(&vcs_indicator);
let input = input::Area::new(&logger, app);
let input = input::Area::new(app);
let visualization = visualization::Container::new(&logger, app, registry);
display_object.add_child(&visualization);
@ -509,16 +504,16 @@ impl NodeModel {
let (x, y) = ERROR_VISUALIZATION_SIZE;
error_visualization.set_size.emit(Vector2(x, y));
let action_bar = action_bar::ActionBar::new(&logger, app);
let action_bar = action_bar::ActionBar::new(app);
display_object.add_child(&action_bar);
scene.layers.above_nodes.add_exclusive(&action_bar);
let output = output::Area::new(&logger, app);
let output = output::Area::new(app);
display_object.add_child(&output);
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet);
let comment = text::Area::new(app);
let comment = text::Text::new(app);
display_object.add_child(&comment);
let app = app.clone_ref();
@ -688,7 +683,7 @@ impl Node {
#[profile(Debug)]
pub fn new(app: &Application, registry: visualization::Registry) -> Self {
let frp = Frp::new();
let network = &frp.private.network;
let network = frp.network();
let out = &frp.private.output;
let input = &frp.private.input;
let model = Rc::new(NodeModel::new(app, registry));
@ -712,11 +707,11 @@ impl Node {
// ths user hovers the drag area. The input port manager merges this information with
// port hover events and outputs the final hover event for any part inside of the node.
let drag_area = &model.drag_area.events;
drag_area_hover <- bool(&drag_area.mouse_out,&drag_area.mouse_over);
let drag_area = &model.drag_area.events;
drag_area_hover <- bool(&drag_area.mouse_out,&drag_area.mouse_over);
model.input.set_hover <+ drag_area_hover;
model.output.set_hover <+ model.input.body_hover;
out.hover <+ model.output.body_hover;
out.hover <+ model.output.body_hover;
// === Background Press ===
@ -750,7 +745,6 @@ impl Node {
// === Comment ===
let comment_base_color = style_frp.get_color(theme::graph_editor::node::text);
// comment_color.target <+ all_with(
comment_color <- all_with(
&comment_base_color, &model.output.expression_label_visibility,
|&base_color,&expression_visible| {
@ -761,14 +755,14 @@ impl Node {
});
color
});
eval comment_color ((value) model.comment.set_color_all(color::Rgba::from(value)));
eval comment_color ((value) model.comment.set_property(.., color::Rgba::from(value)));
eval model.comment.width ([model](width)
model.comment.set_position_x(-*width - COMMENT_MARGIN));
eval model.comment.height ([model](height)
model.comment.set_position_y(*height / 2.0));
model.comment.set_content <+ input.set_comment;
out.comment <+ model.comment.content.map(|text| text.to_string());
out.comment <+ model.comment.content.map(|text| text.to_im_string());
// === Size ===
@ -782,15 +776,15 @@ impl Node {
let visualization_button_state = action_bar.action_visibility.clone_ref();
out.skip <+ action_bar.action_skip;
out.freeze <+ action_bar.action_freeze;
show_action_bar <- out.hover && input.show_quick_action_bar_on_hover;
show_action_bar <- out.hover && input.show_quick_action_bar_on_hover;
eval show_action_bar ((t) action_bar.set_visibility(t));
eval input.show_quick_action_bar_on_hover((value) action_bar.show_on_hover(value));
// === View Mode ===
model.input.set_view_mode <+ input.set_view_mode;
model.output.set_view_mode <+ input.set_view_mode;
model.input.set_view_mode <+ input.set_view_mode;
model.output.set_view_mode <+ input.set_view_mode;
model.profiling_label.set_view_mode <+ input.set_view_mode;
model.vcs_indicator.set_visibility <+ input.set_view_mode.map(|&mode| {
!matches!(mode,view::Mode::Profiling {..})

View File

@ -86,12 +86,11 @@ struct Icons {
}
impl Icons {
fn new(logger: impl AnyLogger) -> Self {
let logger = Logger::new_sub(logger, "Icons");
let display_object = display::object::Instance::new(&logger);
let freeze = ToggleButton::new(&logger);
let visibility = ToggleButton::new(&logger);
let skip = ToggleButton::new(&logger);
fn new() -> Self {
let display_object = display::object::Instance::new();
let freeze = ToggleButton::new();
let visibility = ToggleButton::new();
let skip = ToggleButton::new();
display_object.add_child(&visibility);
// Note: Disabled for https://github.com/enso-org/ide/issues/1397
// Should be re-enabled when https://github.com/enso-org/ide/issues/862 as been implemented.
@ -135,12 +134,11 @@ struct Model {
}
impl Model {
fn new(logger: impl AnyLogger, app: &Application) -> Self {
fn new(app: &Application) -> Self {
let scene = &app.display.default_scene;
let logger = Logger::new_sub(logger, "ActionBar");
let display_object = display::object::Instance::new(&logger);
let hover_area = hover_area::View::new(&logger);
let icons = Icons::new(&logger);
let display_object = display::object::Instance::new();
let hover_area = hover_area::View::new();
let icons = Icons::new();
let shapes = compound::events::MouseEvents::default();
let size = default();
let styles = StyleWatch::new(&scene.style_sheet);
@ -256,8 +254,8 @@ impl Deref for ActionBar {
impl ActionBar {
/// Constructor.
pub fn new(logger: impl AnyLogger, app: &Application) -> Self {
let model = Rc::new(Model::new(logger, app));
pub fn new(app: &Application) -> Self {
let model = Rc::new(Model::new(app));
let frp = Frp::new();
ActionBar { frp, model }.init_frp()
}

View File

@ -93,7 +93,7 @@ impl Container {
pub fn new(scene: &Scene) -> Self {
let scene = scene.clone_ref();
let logger = Logger::new("error::Container");
let display_object = display::object::Instance::new(&logger);
let display_object = display::object::Instance::new();
let background_dom = Self::create_background_dom(&scene);
let visualization = error_visualization::Error::new(&scene);

View File

@ -1,7 +1,7 @@
//! Definition of the node input port component.
use crate::prelude::*;
use enso_text::traits::*;
use enso_text::index::*;
use enso_text::unit::*;
use ensogl::display::shape::*;
use ensogl::display::traits::*;
@ -15,7 +15,7 @@ use crate::Type;
use enso_frp as frp;
use enso_frp;
use enso_text::text::Text;
use enso_text::text::Rope;
use ensogl::application::Application;
use ensogl::data::color;
use ensogl::display;
@ -108,13 +108,13 @@ impl Debug for Expression {
/// Helper struct used for `Expression` conversions.
#[derive(Debug, Default)]
struct ExprConversion {
prev_tok_local_index: Bytes,
prev_tok_local_index: Byte,
/// Index of the last traverse parent node in the `SpanTree`.
last_parent_tok_index: Bytes,
last_parent_tok_index: Byte,
}
impl ExprConversion {
fn new(last_parent_tok_index: Bytes) -> Self {
fn new(last_parent_tok_index: Byte) -> Self {
let prev_tok_local_index = default();
Self { prev_tok_local_index, last_parent_tok_index }
}
@ -126,17 +126,17 @@ impl From<node::Expression> for Expression {
#[profile(Debug)]
fn from(t: node::Expression) -> Self {
// The length difference between `code` and `viz_code` so far.
let mut shift = 0.bytes();
let mut shift = 0.byte();
let mut span_tree = t.input_span_tree.map(|_| port::Model::default());
let mut viz_code = String::new();
let code = t.code;
span_tree.root_ref_mut().dfs_with_layer_data(ExprConversion::default(), |node, info| {
let is_expected_arg = node.is_expected_argument();
let span = node.span();
let mut size = span.size();
let mut size = Byte::try_from(span.size()).unwrap(); // FIXME: hande errors
let mut index = span.start;
let offset_from_prev_tok = node.offset - info.prev_tok_local_index;
info.prev_tok_local_index = node.offset + size;
let offset_from_prev_tok = node.offset - info.prev_tok_local_index.to_diff();
info.prev_tok_local_index = size + node.offset;
viz_code += &" ".repeat(offset_from_prev_tok.as_usize());
if node.children.is_empty() {
viz_code += &code.as_str()[enso_text::Range::new(index, index + size)];
@ -145,16 +145,16 @@ impl From<node::Expression> for Expression {
if is_expected_arg {
if let Some(name) = node.name() {
size = name.len().into();
index += 1.bytes();
shift += 1.bytes() + size;
index += 1.byte();
shift += 1.byte() + size;
viz_code += " ";
viz_code += name;
}
}
let port = node.payload_mut();
port.local_index = index - info.last_parent_tok_index;
port.index = index;
port.length = size;
port.index = index.into();
port.length = size.into();
ExprConversion::new(index)
});
Self { viz_code, code, span_tree }
@ -205,7 +205,7 @@ ensogl::define_endpoints! {
Output {
pointer_style (cursor::Style),
width (f32),
expression (Text),
expression (Rope),
editing (bool),
ports_visible (bool),
body_hover (bool),
@ -220,12 +220,11 @@ ensogl::define_endpoints! {
/// Internal model of the port area.
#[derive(Debug)]
pub struct Model {
logger: Logger,
app: Application,
display_object: display::object::Instance,
ports: display::object::Instance,
header: display::object::Instance,
label: text::Area,
label: text::Text,
expression: RefCell<Expression>,
id_crumbs_map: RefCell<HashMap<ast::Id, Crumbs>>,
styles: StyleWatch,
@ -235,13 +234,12 @@ pub struct Model {
impl Model {
/// Constructor.
#[profile(Debug)]
pub fn new(logger: impl AnyLogger, app: &Application) -> Self {
let logger = Logger::new_sub(&logger, "input_ports");
let display_object = display::object::Instance::new(&logger);
let ports = display::object::Instance::new(&Logger::new_sub(&logger, "ports"));
let header = display::object::Instance::new(&Logger::new_sub(&logger, "header"));
pub fn new(app: &Application) -> Self {
let display_object = display::object::Instance::new();
let ports = display::object::Instance::new();
let header = display::object::Instance::new();
let app = app.clone_ref();
let label = app.new_view::<text::Area>();
let label = app.new_view::<text::Text>();
let id_crumbs_map = default();
let expression = default();
let styles = StyleWatch::new(&app.display.default_scene.style_sheet);
@ -250,7 +248,6 @@ impl Model {
display_object.add_child(&ports);
ports.add_child(&header);
Self {
logger,
app,
display_object,
ports,
@ -273,11 +270,11 @@ impl Model {
self.label.add_to_scene_layer(&scene.layers.label);
let text_color = self.styles.get_color(theme::graph_editor::node::text);
self.label.single_line(true);
self.label.set_single_line_mode(true);
self.label.disable_command("cursor_move_up");
self.label.disable_command("cursor_move_down");
self.label.set_default_color(text_color);
self.label.set_default_text_size(text::Size(TEXT_SIZE));
self.label.set_property_default(text_color);
self.label.set_property_default(text::Size(TEXT_SIZE));
self.label.remove_all_cursors();
let origin = Vector2(TEXT_OFFSET, 0.0);
@ -356,8 +353,8 @@ impl Deref for Area {
impl Area {
/// Constructor.
#[profile(Debug)]
pub fn new(logger: impl AnyLogger, app: &Application) -> Self {
let model = Rc::new(Model::new(logger, app));
pub fn new(app: &Application) -> Self {
let model = Rc::new(Model::new(app));
let frp = Frp::new();
let network = &frp.network;
let selection_color = Animation::new(network);
@ -446,13 +443,13 @@ impl Area {
selection_color_rgba <- profiled.switch(&std_selection_color,&profiled_selection_color);
selection_color.target <+ selection_color_rgba.map(|c| color::Lcha::from(c));
model.label.set_selection_color <+ selection_color.value.map(|&c| color::Rgb::from(c));
model.label.set_selection_color <+ selection_color.value.map(|c| color::Lch::from(c));
init_colors <- source::<()>();
std_base_color <- all(std_base_color,init_colors)._0();
profiled_base_color <- all(profiled_base_color,init_colors)._0();
base_color <- profiled.switch(&std_base_color,&profiled_base_color);
eval base_color ((color) model.label.set_default_color(color));
eval base_color ((color) model.label.set_property_default(color));
init_colors.emit(());
}
@ -464,11 +461,11 @@ impl Area {
let expr = self.model.expression.borrow();
expr.root_ref().get_descendant(crumbs).ok().map(|node| {
let unit = GLYPH_WIDTH;
let range_before = enso_text::Range::new(0.bytes(), node.payload.index);
let char_offset: Chars = expr.viz_code[range_before].chars().count().into();
let char_count: Chars = expr.viz_code[node.payload.range()].chars().count().into();
let width = unit * (i32::from(char_count) as f32);
let x = width / 2.0 + unit * (i32::from(char_offset) as f32);
let range_before = enso_text::Range::new(ByteDiff(0), node.payload.index);
let char_offset = expr.viz_code[range_before].chars().count();
let char_count = expr.viz_code[node.payload.range()].chars().count();
let width = unit * (char_count as f32);
let x = width / 2.0 + unit * (char_offset as f32);
Vector2::new(TEXT_OFFSET + x, 0.0)
})
}
@ -485,7 +482,7 @@ impl Area {
}
#[allow(missing_docs)] // FIXME[everyone] All pub functions should have docs.
pub fn label(&self) -> &text::Area {
pub fn label(&self) -> &text::Text {
&self.model.label
}
@ -516,7 +513,7 @@ struct PortLayerBuilder {
/// The number of chars the expression should be shifted. For example, consider
/// `(foo bar)`, where expression `foo bar` does not get its own port, and thus a 1 char
/// shift should be applied when considering its children.
shift: Chars,
shift: usize,
/// The depth at which the current expression is, where root is at depth 0.
depth: usize,
}
@ -528,7 +525,7 @@ impl PortLayerBuilder {
parent: impl display::Object,
parent_frp: Option<port::FrpEndpoints>,
parent_parensed: bool,
shift: Chars,
shift: usize,
depth: usize,
) -> Self {
let parent = parent.display_object().clone_ref();
@ -546,7 +543,7 @@ impl PortLayerBuilder {
parent: display::object::Instance,
new_parent_frp: Option<port::FrpEndpoints>,
parent_parensed: bool,
shift: Chars,
shift: usize,
) -> Self {
let depth = self.depth + 1;
let parent_frp = new_parent_frp.or_else(|| self.parent_frp.clone());
@ -601,7 +598,7 @@ impl Area {
let range_before_start = node.payload.index - node.payload.local_index;
let range_before_end = node.payload.index;
let range_before = enso_text::Range::new(range_before_start, range_before_end);
let local_char_offset: Chars = code[range_before].chars().count().into();
let local_char_offset = code[range_before].chars().count();
let new_parent = if not_a_port {
builder.parent.clone_ref()
@ -609,17 +606,16 @@ impl Area {
let port = &mut node;
let index = local_char_offset + builder.shift;
let size: Chars = code[port.payload.range()].chars().count().into();
let size = code[port.payload.range()].chars().count();
let unit = GLYPH_WIDTH;
let width = unit * i32::from(size) as f32;
let width = unit * size as f32;
let width_padded = width + 2.0 * PORT_PADDING_X;
let height = 18.0;
let padded_size = Vector2(width_padded, height);
let size = Vector2(width, height);
let logger = &self.model.logger;
let port_shape = port.payload_mut().init_shape(logger, size, node::HEIGHT);
let port_shape = port.payload_mut().init_shape(size, node::HEIGHT);
port_shape.mod_position(|t| t.x = unit * i32::from(index) as f32);
port_shape.mod_position(|t| t.x = unit * index as f32);
if DEBUG {
port_shape.mod_position(|t| t.y = DEBUG_PORT_OFFSET)
}
@ -725,7 +721,7 @@ impl Area {
}
}
let new_parent_frp = Some(node.frp.output.clone_ref());
let new_shift = if !not_a_port { 0.chars() } else { builder.shift + local_char_offset };
let new_shift = if !not_a_port { 0 } else { builder.shift + local_char_offset };
builder.nested(new_parent, new_parent_frp, is_parensed, new_shift)
});
*self.model.id_crumbs_map.borrow_mut() = id_crumbs_map;
@ -826,7 +822,8 @@ impl Area {
set_color <- all_with(&label_color,&self.set_edit_mode,|&color, _| color);
eval set_color ([label](color) {
let range = enso_text::Range::new(index, index + length);
label.set_color_bytes(range,color::Rgba::from(color));
let range = enso_text::Range::<Byte>::try_from(range).unwrap(); // FIXME: handle errors
label.set_property(range,color::Rgba::from(color));
});
}
@ -905,7 +902,7 @@ impl Area {
self.init_port_frp_on_new_expression(&mut new_expression);
self.init_new_expression(new_expression);
if self.frp.editing.value() {
self.model.label.set_cursor_at_end();
self.model.label.set_cursor_at_text_end();
}
}
}

View File

@ -96,10 +96,10 @@ pub struct Shape {
impl Shape {
/// Constructor.
#[profile(Debug)]
pub fn new(logger: &Logger, size: Vector2, hover_height: f32) -> Self {
let root = display::object::Instance::new(logger);
let hover = hover::View::new(logger);
let viz = viz::View::new(logger);
pub fn new(size: Vector2, hover_height: f32) -> Self {
let root = display::object::Instance::new();
let hover = hover::View::new();
let viz = viz::View::new();
let width_padded = size.x + 2.0 * PADDING_X;
hover.size.set(Vector2::new(width_padded, hover_height));
@ -152,9 +152,9 @@ pub struct Model {
pub frp: Frp,
pub shape: Option<Shape>,
pub name: Option<String>,
pub index: Bytes,
pub local_index: Bytes,
pub length: Bytes,
pub index: ByteDiff,
pub local_index: ByteDiff,
pub length: ByteDiff,
pub highlight_color: color::Lcha, // TODO needed? and other fields?
}
@ -176,21 +176,14 @@ impl Model {
/// will be skipped, as there is no point in making them ports. The skip algorithm is
/// implemented as part of the port are initialization.
#[profile(Debug)]
pub fn init_shape(
&mut self,
logger: impl AnyLogger,
size: Vector2,
hover_height: f32,
) -> Shape {
let logger_name = format!("port({},{})", self.index, self.length);
let logger = Logger::new_sub(logger, logger_name);
let shape = Shape::new(&logger, size, hover_height);
pub fn init_shape(&mut self, size: Vector2, hover_height: f32) -> Shape {
let shape = Shape::new(size, hover_height);
self.shape = Some(shape);
self.shape.as_ref().unwrap().clone_ref()
}
/// The range of this port.
pub fn range(&self) -> enso_text::Range<Bytes> {
pub fn range(&self) -> enso_text::Range<ByteDiff> {
let start = self.index;
let end = self.index + self.length;
enso_text::Range::new(start, end)

View File

@ -108,7 +108,7 @@ impl From<node::Expression> for Expression {
span_tree.root_ref_mut().dfs_with_layer_data((), |node, ()| {
let span = node.span();
let port = node.payload_mut();
port.index = span.start;
port.index = span.start.into();
port.length = span.size();
});
Expression { code, span_tree, whole_expr_type, whole_expr_id }
@ -154,11 +154,10 @@ ensogl::define_endpoints! {
/// Internal model of the port area.
#[derive(Debug)]
pub struct Model {
logger: Logger,
app: Application,
display_object: display::object::Instance,
ports: display::object::Instance,
label: text::Area,
label: text::Text,
expression: RefCell<Expression>,
id_crumbs_map: RefCell<HashMap<ast::Id, Crumbs>>,
port_count: Cell<usize>,
@ -170,12 +169,11 @@ pub struct Model {
impl Model {
/// Constructor.
#[profile(Debug)]
pub fn new(logger: impl AnyLogger, app: &Application, frp: &Frp) -> Self {
let logger = Logger::new_sub(&logger, "output_ports");
let display_object = display::object::Instance::new(&logger);
let ports = display::object::Instance::new(&Logger::new_sub(&logger, "ports"));
pub fn new(app: &Application, frp: &Frp) -> Self {
let display_object = display::object::Instance::new();
let ports = display::object::Instance::new();
let app = app.clone_ref();
let label = app.new_view::<text::Area>();
let label = app.new_view::<text::Text>();
let id_crumbs_map = default();
let expression = default();
let port_count = default();
@ -185,7 +183,6 @@ impl Model {
display_object.add_child(&label);
display_object.add_child(&ports);
Self {
logger,
app,
display_object,
ports,
@ -209,11 +206,11 @@ impl Model {
self.label.add_to_scene_layer(&scene.layers.label);
let text_color = self.styles.get_color(theme::graph_editor::node::text);
self.label.single_line(true);
self.label.set_single_line_mode(true);
self.label.disable_command("cursor_move_up");
self.label.disable_command("cursor_move_down");
self.label.set_default_color(text_color);
self.label.set_default_text_size(text::Size(input::area::TEXT_SIZE));
self.label.set_property_default(text_color);
self.label.set_property_default(text::Size(input::area::TEXT_SIZE));
self.label.remove_all_cursors();
self.label.mod_position(|t| t.y = input::area::TEXT_SIZE / 2.0);
@ -367,9 +364,8 @@ impl Model {
if is_a_port {
let port = &mut node;
let crumbs = port.crumbs.clone_ref();
let logger = &self.logger;
let (port_shape,port_frp) = port.payload_mut()
.init_shape(logger,&self.app,&self.styles,&self.styles_frp,port_index
.init_shape(&self.app,&self.styles,&self.styles_frp,port_index
,port_count);
let port_network = &port_frp.network;
@ -466,9 +462,9 @@ impl Deref for Area {
impl Area {
#[allow(missing_docs)] // FIXME[everyone] All pub functions should have docs.
pub fn new(logger: impl AnyLogger, app: &Application) -> Self {
pub fn new(app: &Application) -> Self {
let frp = Frp::new();
let model = Rc::new(Model::new(logger, app, &frp));
let model = Rc::new(Model::new(app, &frp));
let network = &frp.network;
let label_color = color::Animation::new(network);
@ -512,7 +508,7 @@ impl Area {
label_color.target_alpha <+ label_alpha_tgt;
label_color_on_change <- label_color.value.sample(&frp.set_expression);
new_label_color <- any(&label_color.value,&label_color_on_change);
eval new_label_color ((color) model.label.set_color_all(color::Rgba::from(color)));
eval new_label_color ((color) model.label.set_property(.., color::Rgba::from(color)));
// === View Mode ===

View File

@ -383,11 +383,11 @@ macro_rules! fn_multi_only {
impl PortShapeView {
#[profile(Debug)]
fn new(number_of_ports: usize, logger: &Logger) -> Self {
fn new(number_of_ports: usize) -> Self {
if number_of_ports <= 1 {
Self::Single(SinglePortView::new(&logger))
Self::Single(SinglePortView::new())
} else {
Self::Multi(MultiPortView::new(&logger))
Self::Multi(MultiPortView::new())
}
}
@ -452,10 +452,10 @@ ensogl::define_endpoints! {
pub struct Model {
pub frp: Option<Frp>,
pub shape: Option<PortShapeView>,
pub type_label: Option<text::Area>,
pub type_label: Option<text::Text>,
pub display_object: Option<display::object::Instance>,
pub index: Bytes,
pub length: Bytes,
pub index: ByteDiff,
pub length: ByteDiff,
port_count: usize,
port_index: usize,
}
@ -464,16 +464,13 @@ impl Model {
#[allow(missing_docs)] // FIXME[everyone] All pub functions should have docs.
pub fn init_shape(
&mut self,
logger: impl AnyLogger,
app: &Application,
styles: &StyleWatch,
styles_frp: &StyleWatchFrp,
port_index: usize,
port_count: usize,
) -> (display::object::Instance, Frp) {
let logger_name = format!("port({},{})", self.index, self.length);
let logger = Logger::new_sub(logger, logger_name);
let shape = PortShapeView::new(port_count, &logger);
let shape = PortShapeView::new(port_count);
let is_first = port_index == 0;
let is_last = port_index == port_count.saturating_sub(1);
@ -485,13 +482,13 @@ impl Model {
shape.set_padding_right(padding_right);
self.shape = Some(shape.clone());
let type_label = app.new_view::<text::Area>();
let type_label = app.new_view::<text::Text>();
let offset_y =
styles.get_number(ensogl_hardcoded_theme::graph_editor::node::type_label::offset_y);
type_label.set_position_y(offset_y);
self.type_label = Some(type_label.clone());
let display_object = display::object::Instance::new(logger);
let display_object = display::object::Instance::new();
display_object.add_child(&shape);
display_object.add_child(&type_label);
self.display_object = Some(display_object.clone());
@ -506,7 +503,7 @@ impl Model {
fn init_frp(
&mut self,
shape: &PortShapeView,
type_label: &text::Area,
type_label: &text::Text,
styles: &StyleWatch,
styles_frp: &StyleWatchFrp,
) {
@ -577,7 +574,7 @@ impl Model {
showing_full_type <- bool(&full_type_timer.on_reset,&full_type_timer.on_end);
type_description <- all_with(&frp.tp,&showing_full_type,|tp,&show_full_tp| {
tp.map_ref(|tp| {
if show_full_tp { tp.to_string() } else { tp.abbreviate().to_string() }
if show_full_tp { tp.to_im_string() } else { tp.abbreviate().to_im_string() }
})
});
}
@ -588,16 +585,16 @@ impl Model {
// === Type Label ===
type_label_visibility <- frp.on_hover.and(&frp.set_type_label_visibility);
on_type_label_visible <- type_label_visibility.on_true();
type_label_visibility <- frp.on_hover.and(&frp.set_type_label_visibility);
on_type_label_visible <- type_label_visibility.on_true();
type_label_opacity.target <+ on_type_label_visible.constant(PORT_OPACITY_HOVERED);
type_label_opacity.target <+ type_label_visibility.on_false().constant(0.0);
type_label_color <- all_with(&color.value,&type_label_opacity.value,
|color,&opacity| color.opaque.with_alpha(opacity).into());
type_label.set_color_all <+ type_label_color;
type_label.set_default_color <+ type_label_color;
type_label.set_content <+ type_description.map(|s| s.clone().unwrap_or_default());
type_label_color <- all_with(&color.value,&type_label_opacity.value,
|color,&opacity| color.opaque.with_alpha(opacity));
type_label.set_property <+ type_label_color.ref_into_some().map(|t| ((..).into(),*t));
type_label.set_property_default <+ type_label_color.ref_into_some();
type_label.set_content <+ type_description.map(|s| s.clone().unwrap_or_default());
}
}
@ -609,7 +606,7 @@ impl Model {
frp.source.tooltip <+ all_with(&type_description,&frp.on_hover,|text,&hovering| {
if hovering {
if let Some(text) = text.clone() {
tooltip::Style::set_label(text).with_placement(TOOLTIP_LOCATION)
tooltip::Style::set_label(text.into()).with_placement(TOOLTIP_LOCATION)
} else {
tooltip::Style::unset_label()
}

View File

@ -180,7 +180,7 @@ ensogl::define_endpoints! {
#[derive(Clone, CloneRef, Debug)]
pub struct ProfilingLabel {
root: display::object::Instance,
label: text::Area,
label: text::Text,
frp: Frp,
styles: StyleWatchFrp,
}
@ -197,9 +197,9 @@ impl ProfilingLabel {
/// Constructs a `ProfilingLabel` for the given application.
pub fn new(app: &Application) -> Self {
let scene = &app.display.default_scene;
let root = display::object::Instance::new(Logger::new("ProfilingIndicator"));
let root = display::object::Instance::new();
let label = text::Area::new(app);
let label = text::Text::new(app);
root.add_child(&label);
label.set_position_y(crate::component::node::input::area::TEXT_SIZE / 2.0);
label.remove_from_scene_layer(&scene.layers.main);
@ -230,7 +230,7 @@ impl ProfilingLabel {
(&frp.set_status,&frp.set_min_global_duration,&frp.set_max_global_duration,&theme,
|&status,&min,&max,&theme| status.display_color(min,max,theme)
);
label.set_default_color <+ color.value.map(|c| c.into());
label.set_property_default <+ color.value.ref_into_some();
// === Position ===
@ -241,7 +241,7 @@ impl ProfilingLabel {
// === Content ===
label.set_content <+ frp.set_status.map(|status| status.to_string());
label.set_content <+ frp.set_status.map(|status| status.to_im_string());
}
ProfilingLabel { root, label, frp, styles }

View File

@ -88,9 +88,9 @@ struct StatusIndicatorModel {
}
impl StatusIndicatorModel {
fn new(logger: &Logger) -> Self {
let shape = status_indicator_shape::View::new(logger);
let root = display::object::Instance::new(&logger);
fn new() -> Self {
let shape = status_indicator_shape::View::new();
let root = display::object::Instance::new();
root.add_child(&shape);
StatusIndicatorModel { shape, root }
}
@ -145,8 +145,7 @@ pub struct StatusIndicator {
impl StatusIndicator {
/// Constructor.
pub fn new(app: &Application) -> Self {
let logger = Logger::new("status_indicator");
let model = Rc::new(StatusIndicatorModel::new(&logger));
let model = Rc::new(StatusIndicatorModel::new());
let frp = Frp::new();
Self { model, frp }.init_frp(app)
}

Some files were not shown because too many files have changed in this diff Show More