/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/devtools/actors/environment.rs
182 строки
6 KB
Freya Arbjerg
devtools: Add an initial basic autocomplete implementation (#46382)
27 июл 2026, 09:58
Не верифицирован
27 июл 2026, 09:58
6954c43
Код
Авторство
О чём код?
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::collections::HashMap; use atomic_refcell::AtomicRefCell; use devtools_traits::{DebuggerValue, EnvironmentInfo}; use malloc_size_of_derive::MallocSizeOf; use serde::Serialize; use serde_json::Value; use crate::actor::{Actor, ActorEncode, ActorRegistry, new_actor_name}; use crate::actors::console::ConsoleActor; use crate::actors::object::ObjectPropertyDescriptor; use crate::debugger_value_to_json; #[derive(Serialize)] struct EnvironmentBindings { arguments: Vec<Value>, variables: HashMap<String, ObjectPropertyDescriptor>, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct EnvironmentFunction { display_name: String, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub(crate) struct EnvironmentActorMsg { actor: String, #[serde(rename = "type")] type_: Option<String>, scope_kind: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] parent: Option<Box<EnvironmentActorMsg>>, #[serde(skip_serializing_if = "Option::is_none")] bindings: Option<EnvironmentBindings>, /// Should be set if `type_` is `EnvironmentType::Function` #[serde(skip_serializing_if = "Option::is_none")] function: Option<EnvironmentFunction>, /// Should be set if `type_` is `EnvironmentType::Object` #[serde(skip_serializing_if = "Option::is_none")] object: Option<Value>, } /// Resposible for listing the bindings in an environment and assigning new values to them. /// Referenced by `FrameActor` when replying to `getEnvironment` messages. /// <https://searchfox.org/firefox-main/source/devtools/server/actors/environment.js> #[derive(MallocSizeOf)] pub(crate) struct EnvironmentActor { name: String, environment: AtomicRefCell<EnvironmentInfo>, parent_name: Option<String>, } impl Actor for EnvironmentActor { fn name(&self) -> &str { &self.name } } impl EnvironmentActor { pub fn register_or_update( registry: &ActorRegistry, environment: EnvironmentInfo, parent_name: Option<String>, actor_name: Option<String>, ) -> String { if let Some(actor_name) = actor_name { let environment_actor = registry.find::<Self>(&actor_name); *environment_actor.environment.borrow_mut() = environment; return actor_name; } let environment_name = new_actor_name::<Self>(); let environment_actor = Self { name: environment_name.clone(), parent_name, environment: environment.into(), }; registry.register(environment_actor); environment_name } /// Recursively searches for property and variable names in this lineage of environments. /// The resulting vec is sorted and deduplicated. Intended for autocomplete. pub(crate) fn search_identifiers_recursive( &self, registry: &ActorRegistry, prefix: &str, ) -> Vec<String> { let mut names: Vec<String> = vec![]; self.recurse_identifiers(registry, prefix, &mut names); names.sort_unstable(); names.dedup(); names } fn recurse_identifiers(&self, registry: &ActorRegistry, prefix: &str, names: &mut Vec<String>) { let environment = self.environment.borrow(); names.extend( environment .binding_variables .iter() .map(|bind| &bind.name) .filter(|name| ConsoleActor::autocomplete_match(prefix, name)) .cloned(), ); if let Some(DebuggerValue::ObjectValue { preview: Some(preview), .. }) = &environment.object && let Some(props) = &preview.own_properties { names.extend( props .iter() .map(|p| &p.name) .filter(|name| ConsoleActor::autocomplete_match(prefix, name)) .cloned(), ); } if let Some(parent_name) = &self.parent_name { registry .find::<EnvironmentActor>(parent_name) .recurse_identifiers(registry, prefix, names); } } } impl ActorEncode<EnvironmentActorMsg> for EnvironmentActor { fn encode(&self, registry: &ActorRegistry) -> EnvironmentActorMsg { let parent = self .parent_name .as_ref() .map(|p| registry.find::<EnvironmentActor>(p)) .map(|p| Box::new(p.encode(registry))); let environment = self.environment.borrow(); let bindings = match environment.type_.as_deref() { Some("object") | Some("with") => None, _ => Some(EnvironmentBindings { arguments: [].to_vec(), variables: environment .binding_variables .clone() .into_iter() .map(|ref property_descriptor| { ( property_descriptor.name.clone(), ObjectPropertyDescriptor::from_property_descriptor( registry, property_descriptor, ), ) }) .collect(), }), }; EnvironmentActorMsg { actor: self.name().to_string(), type_: environment.type_.clone(), scope_kind: environment.scope_kind.clone(), parent, function: environment .function_display_name .clone() .map(|display_name| EnvironmentFunction { display_name }), object: environment .object .clone() .map(|object| debugger_value_to_json(registry, object)), bindings, } } }