diff --git a/content/blog/memory-system-proposition.mdx b/content/blog/memory-system-proposition.mdx new file mode 100644 index 0000000..db2d068 --- /dev/null +++ b/content/blog/memory-system-proposition.mdx @@ -0,0 +1,66 @@ +--- +title: New Memory System Proposition +author: Klesti Selimaj +date: 2026-05-14 +--- + +First of all i want to thank anyone who used or tried Mist, it's a literal dream project of mine that i attempted many times, years ago. + +And i also released the syntax highlighting VSCode extension: https://marketplace.visualstudio.com/items?itemName=selimaj-dev.mist-syntax + +## Current problem +As i'm developing this language for Rust, i keep noticing the amount of posts of frustration i see online, just like the ones i would make, and i impulsively check out other languages, maybe it's not worth using Rust after all? +The pattern is clear: +- Lifetimes have terrible syntax, and they are hard to understand, even for experienced Rust developers. +- Lifetimes are limiting, making it difficult to express certain patterns where in other languages this would be straightforward. +- The borrow checker can be frustrating, especially for newcomers, and it can lead to a lot of trial and error to get the code to compile. + +## New proposition (Scope Counting) +I want to propose a new memory system (to my understanding), Scope Counting, which you have to see in action to understand it. +```mist +{ + var x = new Box(10); // sc = 0 + + // sc is 0, drop it +} +``` + +```mist +var r; // sc = 0 + +{ + // sc of r = -1 (relative to current scope) + + var x = new Box(10); // sc = 0 + + r = &x; // sc of x = -(sc of r) aka 1 + + // sc is 1, don't drop it, decrement by 1 +} + +// sc is 0, drop it +``` + +This system fixes what Rust couldn't, that is maintaining the same level of safety, without compromising performance and ergonomics, because it's still at the compiler level. + +What makes this better is that it can still live with Rust's lifetime model when needed. + +## More examples +In rust this is a very limiting issue, but with SC, it goes how it's supposed to go +```mist +str* longest(str* x, str* y) { + if (x.len() > y.len()) return x; + else return y; +} +``` + +Why? because both x and y are already a level higher. + +if x is an outer scope of y (generally means lives longer), y would actually push it's sc to live as long as x, a better example is this: +```mist +str* greet() { + return "hello, world!"; // Impossible in Rust +} +``` + +By default, any refrence/allocation is a sc of 0, meaning it's going to last until the current scope ends, but it detected that we are returning it, therefore it increased the sc by 1. diff --git a/content/docs/components/classes.mdx b/content/docs/components/classes.mdx index 1195a3f..081afe2 100644 --- a/content/docs/components/classes.mdx +++ b/content/docs/components/classes.mdx @@ -10,11 +10,11 @@ Classes in Mist bridge the gap between Java's organizational structure and Rust' A class groups fields and methods together. Fields follow the `type name` convention, and methods define their logic directly within the class body. -```cpp -public class Logger { +```mist +pub class Logger { String prefix; - public void info(self*, str* message) { + pub void info(self*, str* message) { self.log(LogLevel::Info, message); } @@ -28,8 +28,8 @@ public class Logger { Unlike languages that use the class name for initialization, Mist uses the explicit `constructor` keyword. This makes the entry point of the class unmistakable. -```cpp -public constructor(str* prefix) { +```mist +pub constructor(str* prefix) { self.prefix = prefix.to_string(); } ``` @@ -38,8 +38,8 @@ public constructor(str* prefix) { Mist maintains Rust's explicit context handling. Any method that needs to access or modify class data must include `self*` (or `self mut*` for mutations) as its first parameter. -```cpp -public void warning(self*, str* message) { +```mist +pub void warning(self*, str* message) { self.log(LogLevel::Warning, message); } ``` @@ -48,7 +48,7 @@ public void warning(self*, str* message) { One of Mist's most powerful features is the ability to nest trait implementations directly within the class block. This keeps the logic for how a type behaves (e.g., how it is displayed) physically coupled with the type definition. -```cpp +```mist impl fmt::Display { std::fmt::Result fmt(self*, std::fmt::Formatter<'_> mut* f) { return write!(f, "logger ({})", self.prefix); @@ -60,5 +60,5 @@ impl fmt::Display { - **Unified Scope**: Data, behavior, and trait logic live in one place, eliminating the friction of jumping between `struct` and `impl` blocks. - **Explicit Context**: The use of `self*` ensures that the relationship between a method and its instance is always transparent. -- **Encapsulation**: Visibility modifiers (`public`) allow you to expose a clean API while keeping internal helper methods and state private to the class. +- **Encapsulation**: Visibility modifiers (`pub`) allow you to expose a clean API while keeping internal helper methods and state private to the class. - **Zero-Cost Classes**: Under the hood, Mist desugars these into idiomatic Rust structs and implementation blocks, ensuring no runtime overhead compared to raw Rust. diff --git a/content/docs/components/enums.mdx b/content/docs/components/enums.mdx index dfc8fa2..c77ca6d 100644 --- a/content/docs/components/enums.mdx +++ b/content/docs/components/enums.mdx @@ -10,8 +10,8 @@ Enums in Mist serve as powerful algebraic data types (ADTs), maintaining the exa An enum can contain unit variants, tuple variants, or struct-like variants. Following Mist's core philosophy, struct-like variants place the type before the identifier. -```rust -public enum TaskState { +```mist +pub enum TaskState { Pending, InProgress, Completed, @@ -26,7 +26,7 @@ public enum TaskState { Mist supports all standard variant shapes, ensuring a 1:1 mapping to the underlying Rust execution model. -```rust +```mist enum Message { Quit, // Unit Move(i32, i32), // Tuple @@ -40,8 +40,8 @@ enum Message { Just like structs and functions, enums declare generics and lifetimes in a unified block. This is particularly useful for defining custom Result or Option types that handle references. -```rust -public enum Validation<'a, T> { +```mist +pub enum Validation<'a, T> { Valid(T), Invalid { str'a* message, @@ -53,5 +53,5 @@ public enum Validation<'a, T> { - **Consistent Member Declaration**: Struct-like variants maintain the `type name` order, ensuring that data modeling feels identical whether you are defining a top-level `struct` or an `enum` variant. - **Rust-Native ADTs**: Enums compile directly to Rust enums, allowing for exhaustive pattern matching and zero-cost abstraction. -- **Shared Visibility**: The `public` modifier at the enum level exports all variants for use in other modules, matching Rust's visibility rules for enums. +- **Shared Visibility**: The `pub` modifier at the enum level exports all variants for use in other modules, matching Rust's visibility rules for enums. - **Comma-Separated Members**: Fields within struct-like variants are separated by commas, mirroring the syntax used in standard Mist structs. diff --git a/content/docs/components/functions.mdx b/content/docs/components/functions.mdx index 9e23aa9..975cb0b 100644 --- a/content/docs/components/functions.mdx +++ b/content/docs/components/functions.mdx @@ -10,7 +10,7 @@ Functions are the primary unit of execution in Mist. They prioritize a tradition A standard function requires a return type, a name, and a body. Use the `void` keyword for functions that do not return a value. -```cpp +```mist i32 add(i32 a, i32 b) { return a + b; } @@ -22,10 +22,10 @@ void log_status(str* message) { ## Visibility & Exports -Functions are private to their module by default. The `public` modifier exports the function for cross-module access. +Functions are private to their module by default. The `pub` modifier exports the function for cross-module access. -```cpp -public i32 get_version() { +```mist +pub i32 get_version() { return 1; } ``` @@ -34,7 +34,7 @@ public i32 get_version() { Parameters follow Rust’s ownership rules but use Mist’s local variable syntax. Use `mut` to allow a function to modify its local binding of a value. -```cpp +```mist void update_score(i32 mut current_score, i32 bonus) { current_score = current_score + bonus; } @@ -44,8 +44,8 @@ void update_score(i32 mut current_score, i32 bonus) { Mist integrates type abstraction and memory management into a single generic block. Lifetimes and type parameters share the `< >` bracket following the identifier. -```rust -public str'a* choose_longer<'a, T: Display>(str'a* s1, str'a* s2, T meta) { +```mist +pub str'a* choose_longer<'a, T: Display>(str'a* s1, str'a* s2, T meta) { println!("Metadata: {}", meta); return if (s1.len() > s2.len()) { s1 } else { s2 }; } @@ -55,9 +55,9 @@ public str'a* choose_longer<'a, T: Display>(str'a* s1, str'a* s2, T meta) { Metadata is applied via the `#[attr]` syntax directly above the declaration for compiler hints or testing. -```cpp +```mist #[inline] -public bool is_active(u32 id) { +pub bool is_active(u32 id) { return id > 0; } ``` diff --git a/content/docs/components/pointers-references.mdx b/content/docs/components/pointers-references.mdx index eb74a20..386a312 100644 --- a/content/docs/components/pointers-references.mdx +++ b/content/docs/components/pointers-references.mdx @@ -10,7 +10,7 @@ Mist simplifies Rust’s reference system by using a pointer-style syntax. While References are defined by placing a `*` after the type. By default, pointers are immutable (shared). To allow modification of the underlying data, use the `mut*` modifier. -```cpp +```mist void increment(i32 mut* value, i32* limit) { if (value < limit) { value = value + 1; @@ -22,10 +22,10 @@ void increment(i32 mut* value, i32* limit) { Lifetimes are attached directly to the type before the pointer symbol. This maintains a clean visual flow where the "type-contract" (identity, duration, and mutability) is read from left to right. -```cpp -public struct Inspector<'a> { - public str'a* target, - public u32'a mut* counter, +```mist +pub struct Inspector<'a> { + pub str'a* target, + pub u32'a mut* counter, } ``` diff --git a/content/docs/components/structs.mdx b/content/docs/components/structs.mdx index 1e04165..70a8c72 100644 --- a/content/docs/components/structs.mdx +++ b/content/docs/components/structs.mdx @@ -10,21 +10,21 @@ Structs in Mist follow the same structural logic as Rust, but apply the language A struct is defined by its name followed by a block of fields. Each field follows the Mist convention of placing the type before the identifier, separated by commas. -```rust -public struct Task { - public String name, - public TaskState state, - public i32 executions, +```mist +pub struct Task { + pub String name, + pub TaskState state, + pub i32 executions, } ``` ## Visibility -Use the `public` modifier to make the struct or its individual fields accessible from other modules. +Use the `pub` modifier to make the struct or its individual fields accessible from other modules. -```cpp -public struct NetworkNode { - public u32 id, +```mist +pub struct NetworkNode { + pub u32 id, str* address, } ``` @@ -33,7 +33,7 @@ public struct NetworkNode { Structs are instantiated using the standard brace syntax. -```cpp +```mist var task = Task { name: "Initialize".to_string(), state: TaskState::Pending, @@ -45,10 +45,10 @@ var task = Task { Generics and lifetimes are declared in angle brackets after the struct name. Lifetimes are associated with the reference/pointer type within the field declarations. -```cpp -public struct Buffer<'a, T> { - public T'a* data, - public usize len, +```mist +pub struct Buffer<'a, T> { + pub T'a* data, + pub usize len, } ``` @@ -57,4 +57,4 @@ public struct Buffer<'a, T> { - **Type-First Declaration**: Fields use the `type name` order to match function parameters and variable declarations. - **Comma-Separated Members**: Fields are separated by commas, maintaining a clean and consistent delimiter style. - **Rust Compatibility**: Maps 1:1 to Rust structs, ensuring zero-cost abstraction and full ecosystem interoperability. -- **Direct Visibility**: The `public` keyword replaces `pub` for a more consistent modifier language across the codebase. +- **Direct Visibility**: The `pub` keyword replaces `pub` for a more consistent modifier language across the codebase. diff --git a/content/docs/components/traits.mdx b/content/docs/components/traits.mdx index 512b3e8..fbef51f 100644 --- a/content/docs/components/traits.mdx +++ b/content/docs/components/traits.mdx @@ -10,8 +10,8 @@ Traits in Mist define a set of methods that a type must implement, facilitating A trait definition lists method signatures that implementing types must satisfy. Like functions, these signatures place the return type before the method name. -```rust -public trait Drawable { +```mist +pub trait Drawable { void draw(self*); str* metadata(self*); } @@ -20,7 +20,7 @@ public trait Drawable { To implement a trait for a specific type, use the `impl` keyword followed by the trait name and the target type. This block must contain all required methods defined in the trait. -```rust +```mist impl Drawable for Task { void draw(self*) { println!("Drawing task: {}", self.name); @@ -35,8 +35,8 @@ impl Drawable for Task { Traits can provide default behavior for methods. Types implementing the trait can choose to override these defaults or use the provided implementation. -```rust -public trait Identifiable { +```mist +pub trait Identifiable { u32 get_id(self*); bool is_valid(self*) { @@ -48,8 +48,8 @@ public trait Identifiable { Traits can build upon other traits. If a trait requires another trait to be implemented first, use the colon `:` syntax. -```rust -public trait Animated : Drawable { +```mist +pub trait Animated : Drawable { void animate(self*, f32 delta_time); } ``` diff --git a/content/docs/index.mdx b/content/docs/index.mdx index 20c8321..e57b7a3 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -64,7 +64,7 @@ path = "build/main.rs" Now for the fun part! Create a new file at `src/main.mist` and add the following code: -```cpp title="src/main.mist" +```mist title="src/main.mist" void main() { println!("Hello World!"); } diff --git a/content/docs/limitations.mdx b/content/docs/limitations.mdx index 07f5988..b55f7fe 100644 --- a/content/docs/limitations.mdx +++ b/content/docs/limitations.mdx @@ -53,7 +53,7 @@ Inheritance is a major planned feature but is currently **not implemented**. Be aware that because we are focusing on syntax, keywords and structures may change between minor versions. Currently: -* **Access Modifiers:** `public` and private defaults are being tested for various contexts (classes vs. structs, or `public(crate)`). +* **Access Modifiers:** `pub` and private defaults are being tested for various contexts (classes vs. structs, or `pub(crate)`). * **Pointers vs. References:** The `*` syntax for references (e.g., `self mut*`) is the current standard but is subject to refinement based on ecosystem feedback. diff --git a/content/docs/logic/control-flow.mdx b/content/docs/logic/control-flow.mdx index 6814709..d51c51a 100644 --- a/content/docs/logic/control-flow.mdx +++ b/content/docs/logic/control-flow.mdx @@ -10,7 +10,7 @@ Control flow in Mist provides a bridge between C-style procedural logic and Rust The `if` statement evaluates a boolean expression. It supports multiple `else if` branches and an optional `else` block. -```cpp +```mist if (score > 50) { println!("Pass"); } else if (score == 50) { @@ -24,7 +24,7 @@ if (score > 50) { The `match` statement provides exhaustive pattern matching. Currently, every match arm requires a block `{}` following the `=>` operator. -```cpp +```mist match (task_state) { TaskState::Pending => { println!("Queued"); @@ -46,7 +46,7 @@ Mist supports both functional iteration and traditional low-level loop control. For manual iteration control, Mist supports the standard three-part `for` loop: initialization, condition, and post-iteration statement. -```cpp +```mist for (var mut i = 0; i < 10; i = i + 1;) { println!("Index: {}", i); } @@ -56,7 +56,7 @@ for (var mut i = 0; i < 10; i = i + 1;) { The `for-in` loop iterates over collections or iterators using Mist's pattern matching system. -```cpp +```mist for (var item in collection) { process(item); } @@ -71,7 +71,7 @@ for ((i32 x, i32 y) in coordinates) { The `while` loop continues execution as long as the parenthesized expression evaluates to `true`. -```cpp +```mist while (active) { wait_for_event(); } diff --git a/content/docs/logic/expressions.mdx b/content/docs/logic/expressions.mdx index 3799efc..62ff96a 100644 --- a/content/docs/logic/expressions.mdx +++ b/content/docs/logic/expressions.mdx @@ -10,7 +10,7 @@ Expressions in Mist are the fundamental units that evaluate to a value. The synt Primary expressions are the starting point of any logic chain. These include literal values, paths to static members, or grouped expressions in tuples. -```java +```mist // Literals and paths var x = 42; var y = Math::PI; @@ -24,7 +24,7 @@ var coordinates = (10, 20, 30); Postfix expressions allow you to build on a primary value. This includes calling functions, accessing fields, indexing arrays, or initializing structs. -```java +```mist // Field access and method/function calls var len = list.length(); @@ -44,7 +44,7 @@ println!("Value: {}", first); // Macro call via '!' Prefixes modify the primary expression that follows them. Mist uses these for logical negation, dereferencing, and creating references. -```java +```mist var mut value = 10; var ref = &value; // Reference @@ -58,7 +58,7 @@ var is_false = !true; // Logical NOT Binary operations are applied as postfixes to an expression, following a `bin_op ~ expr` pattern. This supports all standard arithmetic, comparison, and logical operators. -```java +```mist var sum = 10 + 20; var is_equal = (x == y); var complex = (a + b) * (c / d); diff --git a/content/docs/logic/variables.mdx b/content/docs/logic/variables.mdx index 2f020a2..88bac8d 100644 --- a/content/docs/logic/variables.mdx +++ b/content/docs/logic/variables.mdx @@ -10,7 +10,7 @@ In Mist, variables follow the language-wide `type name` convention. For local sc Variables are declared using the `var` keyword for automatic type inference. Like Rust, variables are immutable by default. -```java +```mist var message = "Hello Mist"; // Inferred as str* var count = 42; // Inferred as i32 ``` @@ -19,7 +19,7 @@ var count = 42; // Inferred as i32 To allow a variable to be reassigned, use the `mut` modifier after the `var` keyword or the explicit type. -```rust +```mist var mut score = 0; score = 100; @@ -31,7 +31,7 @@ price = 14.99; While `var` handles inference, you can explicitly define the type before the identifier. This is often used for clarity in complex logic or when the specific numeric width (e.g., `u8` vs `i32`) matters. -```rust +```mist u64 large_id = 1000234; bool is_active = true; ``` @@ -40,7 +40,7 @@ bool is_active = true; Because variable declarations are patterns, you can destructure tuples or structures directly. This keeps data extraction clean and avoids manual indexing. -```rust +```mist // Destructuring a tuple into local variables (i32, i32) (x, y) = get_coordinates(); @@ -52,7 +52,7 @@ Because variable declarations are patterns, you can destructure tuples or struct Constants are immutable values that are evaluated at compile time. They require an explicit type and follow the `const` keyword. -```rust +```mist const i32 MAX_RETRIES = 5; const str* VERSION = "1.0.4"; ``` diff --git a/public/mist.tmLanguage.json b/public/mist.tmLanguage.json new file mode 100644 index 0000000..a17ff05 --- /dev/null +++ b/public/mist.tmLanguage.json @@ -0,0 +1,231 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "mist", + "scopeName": "source.mist", + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#attributes" + }, + { + "include": "#strings" + }, + { + "include": "#macros" + }, + { + "include": "#type_declarations" + }, + { + "include": "#constants" + }, + { + "include": "#lifetimes" + }, + { + "include": "#generics" + }, + { + "include": "#types" + }, + { + "include": "#namespaces" + }, + { + "include": "#functions" + }, + { + "include": "#numbers" + }, + { + "include": "#operators" + }, + { + "include": "#punctuation" + } + ], + "repository": { + "comments": { + "match": "//.*", + "name": "comment.line.double-slash.mist" + }, + "attributes": { + "begin": "#!?\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.attribute.begin.mist" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.attribute.end.mist" + } + }, + "name": "meta.attribute.mist", + "patterns": [ + { + "include": "$self" + } + ] + }, + "strings": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.mist" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.mist" + } + }, + "name": "string.quoted.double.mist", + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.mist" + } + ] + }, + "macros": { + "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*)(!)", + "captures": { + "1": { + "name": "entity.name.function.macro.mist" + }, + "2": { + "name": "keyword.operator.macro.mist" + } + } + }, + "type_declarations": { + "match": "\\b(struct|enum|class|trait)\\s+([a-zA-Z_][a-zA-Z0-9_]*)", + "captures": { + "1": { + "name": "storage.type.mist" + }, + "2": { + "name": "entity.name.type.mist" + } + } + }, + "keywords": { + "patterns": [ + { + "match": "\\b(if|else|while|for|in|return|break|continue|match)\\b", + "name": "keyword.control.mist" + }, + { + "match": "\\b(struct|enum|class|trait|var)\\b", + "name": "storage.type.mist" + }, + { + "match": "\\b(pub|mut|constructor)\\b", + "name": "storage.modifier.mist" + }, + { + "match": "\\b(impl|use|mod|new|void|self)\\b", + "name": "keyword.other.mist" + } + ] + }, + "constants": { + "match": "\\b(true|false)\\b", + "name": "constant.language.boolean.mist" + }, + "lifetimes": { + "match": "'[a-zA-Z_][a-zA-Z0-9_]*\\b", + "name": "storage.modifier.lifetime.mist" + }, + "generics": { + "begin": "<", + "beginCaptures": { + "0": { + "name": "punctuation.brackets.angle.mist" + } + }, + "end": ">", + "endCaptures": { + "0": { + "name": "punctuation.brackets.angle.mist" + } + }, + "patterns": [ + { + "include": "#lifetimes" + }, + { + "match": "\\b[a-zA-Z_][a-zA-Z0-9_]*\\b", + "name": "entity.name.type.mist" + }, + { + "match": ",", + "name": "punctuation.separator.mist" + }, + { + "match": ":|\\+", + "name": "keyword.operator.mist" + }, + { + "include": "#generics" + } + ] + }, + "types": { + "patterns": [ + { + "match": "(?=|==|!=|&&|\\|\\||\\+|-|\\*|/|%|<|>|=|=>|!)", + "name": "keyword.operator.mist" + }, + "punctuation": { + "match": "::|:|;|,|\\.|\\{|\\}|\\(|\\)|\\[|\\]", + "name": "punctuation.mist" + } + } +} \ No newline at end of file diff --git a/source.config.ts b/source.config.ts index 805f0be..5f14773 100644 --- a/source.config.ts +++ b/source.config.ts @@ -5,6 +5,7 @@ import { } from "fumadocs-mdx/config"; import { metaSchema, pageSchema } from "fumadocs-core/source/schema"; import { z } from "zod"; +import mist from "./public/mist.tmLanguage.json"; // You can customize Zod schemas for frontmatter and `meta.json` here // see https://fumadocs.dev/docs/mdx/collections @@ -33,6 +34,12 @@ export const blogPosts = defineCollections({ export default defineConfig({ mdxOptions: { - // MDX options + rehypeCodeOptions: { + langs: [mist], + themes: { + light: "github-light", + dark: "github-dark", + }, + }, }, }); diff --git a/src/app/(home)/page.tsx b/src/app/(home)/page.tsx index 2ab2049..0f0df47 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -21,7 +21,7 @@ export const mistShowcase = [ greet("Developer"); } -public void greet(str* name) { +pub void greet(str* name) { // Familiar pointer ergonomics with Rust safety String greeting = name.to_string(); println!("Hello, {}!", greeting); @@ -46,19 +46,19 @@ void process_data() { title: "Class and Type System", description: "Classes are syntactic sugar for Rust structs. Using 'extends' provides inheritance-style syntax over struct composition, compiling into the underlying Rust type system.", - code: `public struct PluginInfo { - public String name, - public String version, + code: `pub struct PluginInfo { + pub String name, + pub String version, } -public class PluginRegistry { +pub class PluginRegistry { T plugins; - public constructor(T plugins) { + pub constructor(T plugins) { self.plugins = plugins; } - public T plugins(self) { + pub T plugins(self) { return self.plugins; } }`, @@ -68,10 +68,10 @@ public class PluginRegistry { title: "Better Developer Experience", description: "While Rust can already be a great DX, Mist implements concepts that are proven to improve structure.", - code: `public class Logger { + code: `pub class Logger { String prefix; - public constructor(str* prefix) { + pub constructor(str* prefix) { self.prefix = prefix.to_string(); } diff --git a/src/components/Morph.tsx b/src/components/Morph.tsx index 14944a5..c390ab5 100644 --- a/src/components/Morph.tsx +++ b/src/components/Morph.tsx @@ -1,21 +1,28 @@ "use client"; -import { BundledLanguage, codeToTokens } from "shiki"; +import { BundledLanguage, codeToTokens, createHighlighter } from "shiki"; import { motion, AnimatePresence } from "framer-motion"; import { useEffect, useState } from "react"; +import mist from "../../public/mist.tmLanguage.json"; interface Props { code: string; - lang?: BundledLanguage; } -export default function MorphCode({ code, lang = "rust" }: Props) { +const highlighterPromise = createHighlighter({ + themes: ["github-dark"], + langs: [mist], +}); + +export default function MorphCode({ code }: Props) { const [lines, setLines] = useState([]); useEffect(() => { async function run() { - const result = await codeToTokens(code, { - lang, + const highlighter = await highlighterPromise; + + const result = highlighter.codeToTokens(code, { + lang: "mist" as any, theme: "github-dark", }); @@ -36,7 +43,7 @@ export default function MorphCode({ code, lang = "rust" }: Props) { } run(); - }, [code, lang]); + }, [code]); return (