Share host-aware completion across runtimes
This commit is contained in:
@@ -107,6 +107,42 @@ impl<L: ImportLoader> Engine<L> {
|
||||
thunk
|
||||
}
|
||||
|
||||
/// Returns the values installed in the host-owned global environment.
|
||||
///
|
||||
/// Language tooling uses this after [`crate::HostEnvironment`] configures a
|
||||
/// fresh engine, so editor-visible globals cannot drift from evaluation.
|
||||
pub fn global_values(&mut self) -> Result<Vec<(String, RuntimeValue)>> {
|
||||
let bindings = self.envs[self.prelude_env.0 as usize].bindings.clone();
|
||||
bindings
|
||||
.into_iter()
|
||||
.map(|binding| Ok((binding.name, self.force(binding.value)?)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns the immediately visible fields of an object runtime value.
|
||||
pub fn value_fields(
|
||||
&mut self,
|
||||
value: &RuntimeValue,
|
||||
) -> Result<Option<Vec<(String, RuntimeValue)>>> {
|
||||
let object = match value {
|
||||
RuntimeValue::Concrete(crate::runtime::ConcreteValue::Object(object)) => object,
|
||||
RuntimeValue::Abstract(abstract_value) => {
|
||||
let Some(default) = abstract_value.default else {
|
||||
return Ok(None);
|
||||
};
|
||||
let default = self.force(default)?;
|
||||
return self.value_fields(&default);
|
||||
}
|
||||
_ => return Ok(None),
|
||||
};
|
||||
let fields = object.fields.clone();
|
||||
fields
|
||||
.into_iter()
|
||||
.map(|field| Ok((field.name, self.force(field.value)?)))
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
pub fn add_root_source(
|
||||
&mut self,
|
||||
key: impl Into<String>,
|
||||
|
||||
@@ -23,7 +23,9 @@ pub use diagnostic::{Diagnostic, DiagnosticKind, Result};
|
||||
pub use embedding::{HostField, HostValue};
|
||||
pub use environment::HostEnvironment;
|
||||
pub use eval::{Engine, format_diagnostic_with};
|
||||
pub use module::{EmptyLoader, ImportLoader, LoadedImport, LoadedSource, LoadedValue, Module};
|
||||
pub use module::{
|
||||
EmptyLoader, ImportCandidate, ImportLoader, LoadedImport, LoadedSource, LoadedValue, Module,
|
||||
};
|
||||
pub use parser::{ParseOutput, Parser, SourceForm, parse_source, parse_source_with_source_id};
|
||||
pub use runtime::{Constraint, Data, ExprRef, LiteralValue, ModuleId, PrimitiveType, RuntimeValue};
|
||||
pub use span::{SourceId, Span};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use alloc::string::String;
|
||||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
Ast, ExprId, HostValue, SourceForm, SourceId,
|
||||
@@ -36,6 +36,27 @@ pub enum LoadedImport {
|
||||
Value(LoadedValue),
|
||||
}
|
||||
|
||||
/// An import specifier offered by host-owned language tooling.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ImportCandidate {
|
||||
pub specifier: String,
|
||||
pub detail: Option<String>,
|
||||
}
|
||||
|
||||
impl ImportCandidate {
|
||||
pub fn new(specifier: impl Into<String>) -> Self {
|
||||
Self {
|
||||
specifier: specifier.into(),
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
||||
self.detail = Some(detail.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadedImport {
|
||||
pub fn source(
|
||||
key: impl Into<String>,
|
||||
@@ -59,6 +80,19 @@ impl LoadedImport {
|
||||
|
||||
pub trait ImportLoader {
|
||||
fn load(&mut self, current_key: Option<&str>, specifier: &str) -> crate::Result<LoadedImport>;
|
||||
|
||||
/// Returns host-resolvable import specifiers matching an unfinished prefix.
|
||||
///
|
||||
/// Runtime-only loaders may keep the default implementation. Hosts that
|
||||
/// provide an editor should implement this from the same namespace used by
|
||||
/// [`ImportLoader::load`].
|
||||
fn complete_import(
|
||||
&mut self,
|
||||
_current_key: Option<&str>,
|
||||
_prefix: &str,
|
||||
) -> crate::Result<Vec<ImportCandidate>> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
|
||||
Reference in New Issue
Block a user