add docs for ropes

pull/8675/head
Matt Paras 2025-06-13 23:34:51 -07:00
parent bf2247808c
commit b6b02c8c22
4 changed files with 180 additions and 101 deletions

10
Cargo.lock generated
View File

@ -3220,7 +3220,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "steel-core"
version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#4aeefae1f46f6129fbb70e89c98b8299981cde2a"
source = "git+https://github.com/mattwparas/steel.git#0287954cc6a05bbd794f2636352bf64a71ea176d"
dependencies = [
"abi_stable",
"anyhow",
@ -3273,7 +3273,7 @@ dependencies = [
[[package]]
name = "steel-derive"
version = "0.5.0"
source = "git+https://github.com/mattwparas/steel.git#4aeefae1f46f6129fbb70e89c98b8299981cde2a"
source = "git+https://github.com/mattwparas/steel.git#0287954cc6a05bbd794f2636352bf64a71ea176d"
dependencies = [
"proc-macro2",
"quote",
@ -3283,7 +3283,7 @@ dependencies = [
[[package]]
name = "steel-doc"
version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#4aeefae1f46f6129fbb70e89c98b8299981cde2a"
source = "git+https://github.com/mattwparas/steel.git#0287954cc6a05bbd794f2636352bf64a71ea176d"
dependencies = [
"steel-core",
]
@ -3291,7 +3291,7 @@ dependencies = [
[[package]]
name = "steel-gen"
version = "0.2.0"
source = "git+https://github.com/mattwparas/steel.git#4aeefae1f46f6129fbb70e89c98b8299981cde2a"
source = "git+https://github.com/mattwparas/steel.git#0287954cc6a05bbd794f2636352bf64a71ea176d"
dependencies = [
"codegen",
"serde",
@ -3300,7 +3300,7 @@ dependencies = [
[[package]]
name = "steel-parser"
version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#4aeefae1f46f6129fbb70e89c98b8299981cde2a"
source = "git+https://github.com/mattwparas/steel.git#0287954cc6a05bbd794f2636352bf64a71ea176d"
dependencies = [
"compact_str",
"fxhash",

View File

@ -5,8 +5,11 @@ pub mod steel_implementations {
use steel::{
gc::ShareableMut,
rvals::{as_underlying_type, Custom, SteelString},
steel_vm::{builtin::BuiltInModule, register_fn::RegisterFn},
rvals::{as_underlying_type, AsRefSteelVal, Custom, SteelString},
steel_vm::{
builtin::{BuiltInModule, MarkdownDoc},
register_fn::RegisterFn,
},
SteelVal,
};
@ -19,6 +22,7 @@ pub mod steel_implementations {
impl steel::rvals::Custom for AutoPairConfig {}
impl steel::rvals::Custom for SoftWrap {}
#[allow(unused)]
pub struct RopeyError(ropey::Error);
impl steel::rvals::Custom for RopeyError {}
@ -61,6 +65,10 @@ pub mod steel_implementations {
_ => false,
}
}
fn fmt(&self) -> Option<std::result::Result<String, std::fmt::Error>> {
Some(Ok(format!("#<Rope:\"{}\">", self.to_slice())))
}
}
impl SteelRopeSlice {
@ -90,6 +98,20 @@ pub mod steel_implementations {
}
}
pub fn insert_str(&self, char_idx: usize, text: SteelString) -> Result<Self, RopeyError> {
let slice = self.to_slice();
let mut rope = ropey::Rope::from(slice);
rope.try_insert(char_idx, &text)?;
Ok(Self::new(rope))
}
pub fn insert_char(&self, char_idx: usize, c: char) -> Result<Self, RopeyError> {
let slice = self.to_slice();
let mut rope = ropey::Rope::from(slice);
rope.try_insert_char(char_idx, c)?;
Ok(Self::new(rope))
}
pub fn line(mut self, cursor: usize) -> Result<Self, RopeyError> {
match self.kind {
RangeKind::Char => {
@ -197,6 +219,10 @@ pub mod steel_implementations {
self.to_slice().len_chars()
}
pub fn len_bytes(&self) -> usize {
self.to_slice().len_bytes()
}
pub fn get_char(&self, index: usize) -> Option<char> {
self.to_slice().get_char(index)
}
@ -226,12 +252,6 @@ pub mod steel_implementations {
self
}
pub fn trimmed_starts_with(&self, pat: SteelString) -> bool {
let maybe_owned = Cow::from(self.to_slice());
maybe_owned.trim_start().starts_with(pat.as_str())
}
pub fn starts_with(&self, pat: SteelString) -> bool {
self.to_slice().starts_with(pat.as_str())
}
@ -244,19 +264,142 @@ pub mod steel_implementations {
pub fn rope_module() -> BuiltInModule {
let mut module = BuiltInModule::new("helix/core/text");
module
.register_fn("string->rope", SteelRopeSlice::from_string)
.register_fn("rope->slice", SteelRopeSlice::slice)
.register_fn("rope-char->byte", SteelRopeSlice::char_to_byte)
.register_fn("rope->byte-slice", SteelRopeSlice::byte_slice)
.register_fn("rope->line", SteelRopeSlice::line)
.register_fn("rope->string", SteelRopeSlice::to_string)
.register_fn("rope-len-chars", SteelRopeSlice::len_chars)
.register_fn("rope-char-ref", SteelRopeSlice::get_char)
.register_fn("rope-len-lines", SteelRopeSlice::len_lines)
.register_fn("rope-starts-with?", SteelRopeSlice::starts_with)
.register_fn("rope-ends-with?", SteelRopeSlice::ends_with)
.register_fn("rope-trim-start", SteelRopeSlice::trim_start);
macro_rules! register_value {
($name:expr, $func:expr, $doc:expr) => {
module.register_fn($name, $func);
module.register_doc($name, MarkdownDoc(Cow::Borrowed($doc)));
};
}
register_value!(
"Rope?",
|value: SteelVal| SteelRopeSlice::as_ref(&value).is_ok(),
"Check if the given value is a rope"
);
register_value!(
"string->rope",
SteelRopeSlice::from_string,
r#"Converts a string into a rope.
```scheme
(string->rope value) -> Rope?
```
* value : string?
"#
);
register_value!(
"rope->slice",
SteelRopeSlice::slice,
r#"Take a slice from using character indices from the rope.
Returns a new rope value.
```scheme
(rope->slice rope start end) -> Rope?
```
* rope : Rope?
* start: (and positive? int?)
* end: (and positive? int?)
"#
);
register_value!(
"rope-char->byte",
SteelRopeSlice::char_to_byte,
r#"Convert the character offset into a byte offset for a given rope"#
);
register_value!(
"rope->byte-slice",
SteelRopeSlice::byte_slice,
r#"Take a slice of this rope using byte offsets
```scheme
(rope->byte-slice rope start end) -> Rope?
```
* rope: Rope?
* start: (and positive? int?)
* end: (and positive? int?)
"#
);
register_value!(
"rope->line",
SteelRopeSlice::line,
r#"Get the line at the given line index. Returns a rope.
```scheme
(rope->line rope index) -> Rope?
```
* rope : Rope?
* index : (and positive? int?)
"#
);
register_value!(
"rope->string",
SteelRopeSlice::to_string,
"Convert the given rope to a string"
);
register_value!(
"rope-len-chars",
SteelRopeSlice::len_chars,
"Get the length of the rope in characters"
);
register_value!(
"rope-len-bytes",
SteelRopeSlice::len_chars,
"Get the length of the rope in bytes"
);
register_value!(
"rope-char-ref",
SteelRopeSlice::get_char,
"Get the character at the given index"
);
register_value!(
"rope-len-lines",
SteelRopeSlice::len_lines,
"Get the number of lines in the rope"
);
register_value!(
"rope-starts-with?",
SteelRopeSlice::starts_with,
"Check if the rope starts with a given pattern"
);
register_value!(
"rope-ends-with?",
SteelRopeSlice::ends_with,
"Check if the rope ends with a given pattern"
);
register_value!(
"rope-trim-start",
SteelRopeSlice::trim_start,
"Remove the leading whitespace from the given rope"
);
register_value!(
"rope-insert-string",
SteelRopeSlice::insert_str,
"Insert a string at the given index into the rope"
);
register_value!(
"rope-insert-char",
SteelRopeSlice::insert_char,
"Insert a character at the given index"
);
module
}

View File

@ -3280,6 +3280,15 @@ fn configure_lsp_builtins(name: &str, module: &BuiltInModule) {
output.push_str("))");
for value in module.names() {
if let Some(doc) = module.get_documentation(&value) {
output.push_str(&format!(
"(#%module-add-doc #%helix-{}-module {:?} {:?})\n",
name, value, doc
));
}
}
std::fs::write(path, output).unwrap();
}
@ -3294,80 +3303,6 @@ fn load_rope_api(engine: &mut Engine, generate_sources: bool) {
engine.register_module(rope_slice_module);
}
// struct SteelEngine(Engine);
// impl SteelEngine {
// pub fn call_function_by_name(
// &mut self,
// function_name: SteelString,
// args: Vec<SteelVal>,
// ) -> steel::rvals::Result<SteelVal> {
// self.0
// .call_function_by_name_with_args(function_name.as_str(), args.into_iter().collect())
// }
// /// Calling a function that was not defined in the runtime it was created in could
// /// result in panics. You have been warned.
// pub fn call_function(
// &mut self,
// function: SteelVal,
// args: Vec<SteelVal>,
// ) -> steel::rvals::Result<SteelVal> {
// self.0
// .call_function_with_args(function, args.into_iter().collect())
// }
// pub fn require_module(&mut self, module: SteelString) -> steel::rvals::Result<()> {
// self.0.run(format!("(require \"{}\")", module)).map(|_| ())
// }
// }
// impl Custom for SteelEngine {}
// static ENGINE_ID: AtomicUsize = AtomicUsize::new(0);
// thread_local! {
// pub static ENGINE_MAP: SteelVal =
// SteelVal::boxed(SteelVal::empty_hashmap());
// }
// Low level API work, these need to be loaded into the global environment in a predictable
// location, otherwise callbacks from plugin engines will not be handled properly!
// fn load_engine_api(engine: &mut Engine) {
// fn id_to_engine(value: SteelVal) -> Option<SteelVal> {
// if let SteelVal::Boxed(b) = ENGINE_MAP.with(|x| x.clone()) {
// if let SteelVal::HashMapV(h) = b.read().clone() {
// return h.get(&value).cloned();
// }
// }
// None
// }
// // module
// engine
// .register_fn("helix.controller.create-engine", || {
// SteelEngine(configure_engine_impl(Engine::new()))
// })
// .register_fn("helix.controller.fresh-engine-id", || {
// ENGINE_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
// })
// .register_fn(
// "helix.controller.call-function-by-name",
// SteelEngine::call_function_by_name,
// )
// .register_fn("helix.controller.call-function", SteelEngine::call_function)
// .register_fn(
// "helix.controller.require-module",
// SteelEngine::require_module,
// )
// .register_value(
// "helix.controller.engine-map",
// ENGINE_MAP.with(|x| x.clone()),
// )
// .register_fn("helix.controller.id->engine", id_to_engine);
// }
fn load_misc_api(engine: &mut Engine, generate_sources: bool) {
let mut module = BuiltInModule::new("helix/core/misc");

View File

@ -2,7 +2,7 @@ use helix_event::{events, register_event};
use helix_view::document::Mode;
use helix_view::events::{
DiagnosticsDidChange, DocumentDidChange, DocumentDidClose, DocumentDidOpen, DocumentFocusLost,
LanguageServerExited, LanguageServerInitialized, SelectionDidChange,
DocumentSaved, LanguageServerExited, LanguageServerInitialized, SelectionDidChange,
};
use crate::commands;
@ -22,6 +22,7 @@ pub fn register() {
register_event::<DocumentDidChange>();
register_event::<DocumentDidClose>();
register_event::<DocumentFocusLost>();
register_event::<DocumentSaved>();
register_event::<SelectionDidChange>();
register_event::<DiagnosticsDidChange>();
register_event::<LanguageServerInitialized>();