From 963c91ba755844190b24a91843ab07e727fa842d Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Thu, 24 Sep 2026 20:10:11 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E9=BD=90=20String=20Annex=20B?= =?UTF-8?q?=20HTML=20=E5=8C=85=E8=A3=85=E6=96=B9=E6=B3=95=E6=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/string/basic.rs | 141 ++++++++++++++++++++ crates/oxide_kernel/src/builtin/bind.rs | 13 ++ crates/oxide_kernel/src/builtin/methods.rs | 13 ++ crates/oxide_vm/src/bindings/bind_string.rs | 13 ++ 4 files changed, 180 insertions(+) diff --git a/crates/oxide_builtins/src/string/basic.rs b/crates/oxide_builtins/src/string/basic.rs index 28b27218..22589703 100644 --- a/crates/oxide_builtins/src/string/basic.rs +++ b/crates/oxide_builtins/src/string/basic.rs @@ -763,3 +763,144 @@ pub fn string_ends_with(vm: &mut H, args: &[u8]) -> NativeResult { let result = if search.is_empty() { true } else { s[..end_pos].ends_with(&search) }; NativeResult::Ok(JsValue::bool(result)) } + +// ── Annex B HTML 方法族 ───────────────────────────────────────────────── +// +// 13 个 HTML 包装方法共用 CreateHTML 语义:this 经 RequireObjectCoercible + +// ToString 后拼 `串`;attr 为空串则无属性段,属性值 +// 经完整 ToString(缺参得 "undefined"),值内 0x0022(双引号)替换为 +// `"`,其余单元原样保留。 + +/// CreateHTML 语义拼接:`串` 片段;attr 为空则无属性段, +/// 属性值内 0x0022 替换为 `"`。 +fn create_html(s: &[u16], tag: &str, attr: &str, attr_value: &[u16]) -> Vec { + let mut out = Vec::with_capacity(s.len() + tag.len() * 2 + attr.len() + attr_value.len() * 2 + 8); + out.push(b'<' as u16); + out.extend(tag.encode_utf16()); + if !attr.is_empty() { + out.push(b' ' as u16); + out.extend(attr.encode_utf16()); + out.push(b'=' as u16); + out.push(b'"' as u16); + for &u in attr_value { + if u == 0x0022 { + out.extend(b""".iter().map(|&b| b as u16)); + } else { + out.push(u); + } + } + out.push(b'"' as u16); + } + out.push(b'>' as u16); + out.extend_from_slice(s); + out.push(b'<' as u16); + out.push(b'/' as u16); + out.extend(tag.encode_utf16()); + out.push(b'>' as u16); + out +} + +/// `String.prototype.anchor(name)`:返回 `串` 形 HTML 片段; +/// 属性值经完整 ToString(缺参得 "undefined"),值内双引号替换为 `"`。 +pub fn string_anchor(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.anchor called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let v: Vec = try_string!(as_units(vm, val)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "a", "name", &v))) +} + +/// `String.prototype.big()`:返回 `串` 形 HTML 片段。 +pub fn string_big(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.big called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "big", "", &[]))) +} + +/// `String.prototype.blink()`:返回 `串` 形 HTML 片段。 +pub fn string_blink(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.blink called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "blink", "", &[]))) +} + +/// `String.prototype.bold()`:返回 `串` 形 HTML 片段。 +pub fn string_bold(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.bold called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "b", "", &[]))) +} + +/// `String.prototype.fixed()`:返回 `串` 形 HTML 片段。 +pub fn string_fixed(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.fixed called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "tt", "", &[]))) +} + +/// `String.prototype.fontcolor(colour)`:返回 `串` 形 +/// HTML 片段;属性值经完整 ToString(缺参得 "undefined"),值内双引号替换为 +/// `"`。 +pub fn string_fontcolor(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.fontcolor called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let v: Vec = try_string!(as_units(vm, val)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "font", "color", &v))) +} + +/// `String.prototype.fontsize(size)`:返回 `串` 形 +/// HTML 片段;属性值经完整 ToString(缺参得 "undefined"),值内双引号替换为 +/// `"`。 +pub fn string_fontsize(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.fontsize called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let v: Vec = try_string!(as_units(vm, val)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "font", "size", &v))) +} + +/// `String.prototype.italics()`:返回 `串` 形 HTML 片段。 +pub fn string_italics(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.italics called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "i", "", &[]))) +} + +/// `String.prototype.link(url)`:返回 `串` 形 HTML 片段; +/// 属性值经完整 ToString(缺参得 "undefined"),值内双引号替换为 `"`。 +pub fn string_link(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.link called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let v: Vec = try_string!(as_units(vm, val)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "a", "href", &v))) +} + +/// `String.prototype.small()`:返回 `串` 形 HTML 片段。 +pub fn string_small(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.small called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "small", "", &[]))) +} + +/// `String.prototype.strike()`:返回 `串` 形 HTML 片段。 +pub fn string_strike(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.strike called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "strike", "", &[]))) +} + +/// `String.prototype.sub()`:返回 `串` 形 HTML 片段。 +pub fn string_sub(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.sub called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "sub", "", &[]))) +} + +/// `String.prototype.sup()`:返回 `串` 形 HTML 片段。 +pub fn string_sup(vm: &mut H, args: &[u8]) -> NativeResult { + builtins_debug!("String.prototype.sup called with {} args", args.len()); + let s: Vec = try_string!(this_units(vm, args)).into_owned(); + NativeResult::Ok(vm.new_string_units_owned(create_html(&s, "sup", "", &[]))) +} diff --git a/crates/oxide_kernel/src/builtin/bind.rs b/crates/oxide_kernel/src/builtin/bind.rs index 230305c9..dc565a22 100644 --- a/crates/oxide_kernel/src/builtin/bind.rs +++ b/crates/oxide_kernel/src/builtin/bind.rs @@ -281,6 +281,19 @@ impl BuiltinWorld { ("lastIndexOf", methods.last_index_of, 1), ("isWellFormed", methods.is_well_formed, 0), ("toWellFormed", methods.to_well_formed, 0), + ("anchor", methods.anchor, 1), + ("big", methods.big, 0), + ("blink", methods.blink, 0), + ("bold", methods.bold, 0), + ("fixed", methods.fixed, 0), + ("fontcolor", methods.fontcolor, 1), + ("fontsize", methods.fontsize, 1), + ("italics", methods.italics, 0), + ("link", methods.link, 1), + ("small", methods.small, 0), + ("strike", methods.strike, 0), + ("sub", methods.sub, 0), + ("sup", methods.sup, 0), ); } diff --git a/crates/oxide_kernel/src/builtin/methods.rs b/crates/oxide_kernel/src/builtin/methods.rs index ec575cdd..df46e4f7 100644 --- a/crates/oxide_kernel/src/builtin/methods.rs +++ b/crates/oxide_kernel/src/builtin/methods.rs @@ -126,6 +126,19 @@ pub struct StringMethods { pub to_locale_lower_case: *const (), pub to_locale_upper_case: *const (), pub locale_compare: *const (), + pub anchor: *const (), + pub big: *const (), + pub blink: *const (), + pub bold: *const (), + pub fixed: *const (), + pub fontcolor: *const (), + pub fontsize: *const (), + pub italics: *const (), + pub link: *const (), + pub small: *const (), + pub strike: *const (), + pub sub: *const (), + pub sup: *const (), } /// RegExp 原型方法的 native 函数指针集合。 diff --git a/crates/oxide_vm/src/bindings/bind_string.rs b/crates/oxide_vm/src/bindings/bind_string.rs index b1ba9387..6e5b9146 100644 --- a/crates/oxide_vm/src/bindings/bind_string.rs +++ b/crates/oxide_vm/src/bindings/bind_string.rs @@ -46,6 +46,19 @@ pub fn bind_string(core: &Arc, session: &KernelSession, global: &mut is_well_formed: oxide_builtins::string::string_is_well_formed:: as *const (), to_well_formed: oxide_builtins::string::string_to_well_formed:: as *const (), from_raw: oxide_builtins::string::string_raw:: as *const (), + anchor: oxide_builtins::string::string_anchor:: as *const (), + big: oxide_builtins::string::string_big:: as *const (), + blink: oxide_builtins::string::string_blink:: as *const (), + bold: oxide_builtins::string::string_bold:: as *const (), + fixed: oxide_builtins::string::string_fixed:: as *const (), + fontcolor: oxide_builtins::string::string_fontcolor:: as *const (), + fontsize: oxide_builtins::string::string_fontsize:: as *const (), + italics: oxide_builtins::string::string_italics:: as *const (), + link: oxide_builtins::string::string_link:: as *const (), + small: oxide_builtins::string::string_small:: as *const (), + strike: oxide_builtins::string::string_strike:: as *const (), + sub: oxide_builtins::string::string_sub:: as *const (), + sup: oxide_builtins::string::string_sup:: as *const (), }; session.builtin_world().bind_string_methods( &string_methods,