Stationpedia docs
This commit is contained in:
@@ -3,6 +3,7 @@ namespace Slang;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Assets.Scripts.UI;
|
||||||
using StationeersIC10Editor;
|
using StationeersIC10Editor;
|
||||||
|
|
||||||
public static unsafe class SlangExtensions
|
public static unsafe class SlangExtensions
|
||||||
@@ -133,4 +134,34 @@ public static unsafe class SlangExtensions
|
|||||||
return SlangFormatter.ColorDefault;
|
return SlangFormatter.ColorDefault;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static unsafe List<StationpediaPage> ToList(this Vec_FfiDocumentedItem_t vec)
|
||||||
|
{
|
||||||
|
var toReturn = new List<StationpediaPage>((int)vec.len);
|
||||||
|
|
||||||
|
var currentPtr = vec.ptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)vec.len; i++)
|
||||||
|
{
|
||||||
|
var doc = currentPtr[i];
|
||||||
|
var docItemName = doc.item_name.AsString();
|
||||||
|
|
||||||
|
var formattedText = TextMeshProFormatter.FromMarkdown(doc.docs.AsString());
|
||||||
|
|
||||||
|
var pediaPage = new StationpediaPage(
|
||||||
|
$"slang-item-{docItemName}",
|
||||||
|
docItemName,
|
||||||
|
formattedText
|
||||||
|
);
|
||||||
|
|
||||||
|
pediaPage.Text = formattedText;
|
||||||
|
pediaPage.Description = formattedText;
|
||||||
|
pediaPage.ParsePage();
|
||||||
|
|
||||||
|
toReturn.Add(pediaPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ffi.free_docs_vec(vec);
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,31 @@ public unsafe partial class Ffi {
|
|||||||
slice_ref_uint16_t input);
|
slice_ref_uint16_t input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 48)]
|
||||||
|
public unsafe struct FfiDocumentedItem_t {
|
||||||
|
public Vec_uint8_t item_name;
|
||||||
|
|
||||||
|
public Vec_uint8_t docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Same as [<c>Vec<T></c>][<c>rust::Vec</c>], but with guaranteed <c>#[repr(C)]</c> layout
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 24)]
|
||||||
|
public unsafe struct Vec_FfiDocumentedItem_t {
|
||||||
|
public FfiDocumentedItem_t * ptr;
|
||||||
|
|
||||||
|
public UIntPtr len;
|
||||||
|
|
||||||
|
public UIntPtr cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe partial class Ffi {
|
||||||
|
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
|
||||||
|
void free_docs_vec (
|
||||||
|
Vec_FfiDocumentedItem_t v);
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe partial class Ffi {
|
public unsafe partial class Ffi {
|
||||||
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
|
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
|
||||||
void free_ffi_diagnostic_vec (
|
void free_ffi_diagnostic_vec (
|
||||||
@@ -164,6 +189,11 @@ public unsafe partial class Ffi {
|
|||||||
Vec_uint8_t s);
|
Vec_uint8_t s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public unsafe partial class Ffi {
|
||||||
|
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
|
||||||
|
Vec_FfiDocumentedItem_t get_docs ();
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe partial class Ffi {
|
public unsafe partial class Ffi {
|
||||||
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
|
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
|
||||||
Vec_FfiToken_t tokenize_line (
|
Vec_FfiToken_t tokenize_line (
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Assets.Scripts.UI;
|
||||||
using StationeersIC10Editor;
|
using StationeersIC10Editor;
|
||||||
|
|
||||||
public struct Range
|
public struct Range
|
||||||
@@ -151,6 +152,14 @@ public static class Marshal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the currently documented items from the Slang compiler and returns new StationpediaPages with correct formatting.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe List<StationpediaPage> GetSlangDocs()
|
||||||
|
{
|
||||||
|
return Ffi.get_docs().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
private static string ExtractNativeLibrary(string libName)
|
private static string ExtractNativeLibrary(string libName)
|
||||||
{
|
{
|
||||||
string destinationPath = Path.Combine(Path.GetTempPath(), libName);
|
string destinationPath = Path.Combine(Path.GetTempPath(), libName);
|
||||||
|
|||||||
@@ -224,4 +224,14 @@ public static class SlangPatches
|
|||||||
_currentlyEditingMotherboard = null;
|
_currentlyEditingMotherboard = null;
|
||||||
_motherboardCachedCode = null;
|
_motherboardCachedCode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Stationpedia), nameof(Stationpedia.Regenerate))]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void Stationpedia_Regenerate()
|
||||||
|
{
|
||||||
|
foreach (var page in Marshal.GetSlangDocs())
|
||||||
|
{
|
||||||
|
Stationpedia.Register(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
using Assets.Scripts.UI;
|
|
||||||
|
|
||||||
namespace Slang
|
|
||||||
{
|
|
||||||
public static class SlangDocs
|
|
||||||
{
|
|
||||||
public static StationpediaPage[] Pages
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return
|
|
||||||
[
|
|
||||||
new StationpediaPage(
|
|
||||||
"slang-init",
|
|
||||||
"Slang",
|
|
||||||
"Slang is a new high level language built specifically for Stationeers"
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
54
csharp_mod/TmpFormatter.cs
Normal file
54
csharp_mod/TmpFormatter.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Slang;
|
||||||
|
|
||||||
|
public static class TextMeshProFormatter
|
||||||
|
{
|
||||||
|
private const string CODE_COLOR = "#FFD700";
|
||||||
|
|
||||||
|
public static string FromMarkdown(string markdown)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(markdown))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
// 1. Normalize Line Endings
|
||||||
|
string text = markdown.Replace("\r\n", "\n");
|
||||||
|
|
||||||
|
// 2. Handle Code Blocks (```)
|
||||||
|
text = Regex.Replace(
|
||||||
|
text,
|
||||||
|
@"```\s*(.*?)\s*```",
|
||||||
|
match =>
|
||||||
|
{
|
||||||
|
var codeContent = match.Groups[1].Value;
|
||||||
|
return $"<color={CODE_COLOR}>{codeContent}</color>"; // Gold color for code
|
||||||
|
},
|
||||||
|
RegexOptions.Singleline
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. Handle Headers (## Header)
|
||||||
|
// Convert ## Header to large bold text
|
||||||
|
text = Regex.Replace(
|
||||||
|
text,
|
||||||
|
@"^##(\s+)?(.+)$",
|
||||||
|
"<size=120%><b>$1</b></size>",
|
||||||
|
RegexOptions.Multiline
|
||||||
|
);
|
||||||
|
|
||||||
|
// 4. Handle Inline Code (`code`)
|
||||||
|
text = Regex.Replace(text, @"`([^`]+)`", $"<color={CODE_COLOR}>$1</color>");
|
||||||
|
|
||||||
|
// 5. Handle Bold (**text**)
|
||||||
|
text = Regex.Replace(text, @"\*\*(.+?)\*\*", "<b>$1</b>");
|
||||||
|
|
||||||
|
// 6. Handle Italics (*text*)
|
||||||
|
text = Regex.Replace(text, @"\*(.+?)\*", "<i>$1</i>");
|
||||||
|
|
||||||
|
// 7. Convert Newlines to TMP Line Breaks
|
||||||
|
// Stationpedia needs <br> or explicit newlines.
|
||||||
|
// Often just ensuring \n is preserved is enough, but <br> is safer for HTML-like parsers.
|
||||||
|
text = text.Replace("\n", "<br>");
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ mod macros;
|
|||||||
pub trait Documentation {
|
pub trait Documentation {
|
||||||
/// Retreive documentation for this specific item.
|
/// Retreive documentation for this specific item.
|
||||||
fn docs(&self) -> String;
|
fn docs(&self) -> String;
|
||||||
|
|
||||||
|
fn get_all_documentation() -> Vec<(&'static str, String)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ macro_rules! documented {
|
|||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Implement the Trait
|
// 2. Implement the Documentation Trait
|
||||||
impl Documentation for $name {
|
impl Documentation for $name {
|
||||||
fn docs(&self) -> String {
|
fn docs(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
@@ -79,6 +79,33 @@ macro_rules! documented {
|
|||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Implement Static Documentation Provider
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn get_all_documentation() -> Vec<(&'static str, String)> {
|
||||||
|
vec![
|
||||||
|
$(
|
||||||
|
(
|
||||||
|
stringify!($variant),
|
||||||
|
{
|
||||||
|
// Re-use the same extraction logic
|
||||||
|
let doc_lines: &[Option<&str>] = &[
|
||||||
|
$(
|
||||||
|
documented!(@doc_filter #[ $($variant_attr)* ])
|
||||||
|
),*
|
||||||
|
];
|
||||||
|
doc_lines.iter()
|
||||||
|
.filter_map(|&d| d)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),*
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,6 +236,13 @@ impl Documentation for SysCall {
|
|||||||
Self::Math(m) => m.docs(),
|
Self::Math(m) => m.docs(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_all_documentation() -> Vec<(&'static str, String)> {
|
||||||
|
let mut all_docs = System::get_all_documentation();
|
||||||
|
all_docs.extend(Math::get_all_documentation());
|
||||||
|
|
||||||
|
all_docs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for SysCall {
|
impl std::fmt::Display for SysCall {
|
||||||
|
|||||||
@@ -95,6 +95,10 @@ impl Documentation for TokenType {
|
|||||||
_ => "".into(),
|
_ => "".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_all_documentation() -> Vec<(&'static str, String)> {
|
||||||
|
Keyword::get_all_documentation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TokenType> for u32 {
|
impl From<TokenType> for u32 {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use compiler::Compiler;
|
use compiler::Compiler;
|
||||||
use helpers::Documentation;
|
use helpers::Documentation;
|
||||||
use parser::Parser;
|
use parser::{sys_call::SysCall, Parser};
|
||||||
use safer_ffi::prelude::*;
|
use safer_ffi::prelude::*;
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
use tokenizer::{
|
use tokenizer::{
|
||||||
@@ -27,6 +27,13 @@ pub struct FfiRange {
|
|||||||
end_line: u32,
|
end_line: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive_ReprC]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct FfiDocumentedItem {
|
||||||
|
item_name: safer_ffi::String,
|
||||||
|
docs: safer_ffi::String,
|
||||||
|
}
|
||||||
|
|
||||||
impl From<lsp_types::Range> for FfiRange {
|
impl From<lsp_types::Range> for FfiRange {
|
||||||
fn from(value: lsp_types::Range) -> Self {
|
fn from(value: lsp_types::Range) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -77,6 +84,11 @@ pub fn free_string(s: safer_ffi::String) {
|
|||||||
drop(s)
|
drop(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[ffi_export]
|
||||||
|
pub fn free_docs_vec(v: safer_ffi::Vec<FfiDocumentedItem>) {
|
||||||
|
drop(v)
|
||||||
|
}
|
||||||
|
|
||||||
/// C# handles strings as UTF16. We do NOT want to allocate that memory in C# because
|
/// C# handles strings as UTF16. We do NOT want to allocate that memory in C# because
|
||||||
/// we want to avoid GC. So we pass it to Rust to handle all the memory allocations.
|
/// we want to avoid GC. So we pass it to Rust to handle all the memory allocations.
|
||||||
/// This should result in the ability to compile many times without triggering frame drops
|
/// This should result in the ability to compile many times without triggering frame drops
|
||||||
@@ -184,3 +196,26 @@ pub fn diagnose_source(input: safer_ffi::slice::Ref<'_, u16>) -> safer_ffi::Vec<
|
|||||||
|
|
||||||
res.unwrap_or(vec![].into())
|
res.unwrap_or(vec![].into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[ffi_export]
|
||||||
|
pub fn get_docs() -> safer_ffi::Vec<FfiDocumentedItem> {
|
||||||
|
let res = std::panic::catch_unwind(|| {
|
||||||
|
let mut docs = SysCall::get_all_documentation();
|
||||||
|
docs.extend(TokenType::get_all_documentation());
|
||||||
|
|
||||||
|
docs
|
||||||
|
});
|
||||||
|
|
||||||
|
let Ok(result) = res else {
|
||||||
|
return vec![].into();
|
||||||
|
};
|
||||||
|
|
||||||
|
result
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, doc)| FfiDocumentedItem {
|
||||||
|
item_name: key.into(),
|
||||||
|
docs: doc.into(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user