When using multiple line text, add the ability to write an element inside an element:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NoirCode Studio</title>
    <style>
        /* Reset some default styles */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html, body {
            height: 100%;
        }

        body {
            background-color: #1e1e1e;
            color: #cccccc;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            flex-direction: column;
        }

        header {
            background-color: #252526;
            padding: 15px 20px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            font-size: 1.5rem;
            font-weight: bold;
            border-bottom: 1px solid #333;
            position: relative;
        }

        /* Tabs for Mobile */
        .tabs {
            display: none; /* Hidden by default, shown on mobile */
        }

        .tabs button {
            background: none;
            border: none;
            color: #cccccc;
            padding: 10px 15px;
            cursor: pointer;
            font-size: 1rem;
            transition: background-color 0.3s;
        }

        .tabs button.active, .tabs button:hover {
            background-color: #3a3a3a;
            border-radius: 4px;
        }

        .container {
            flex: 1;
            display: flex;
            overflow: hidden;
        }

        .editor, .preview {
            flex: 1;
            padding: 20px;
            overflow: auto;
        }

        .editor {
            background-color: #1e1e1e;
            border-right: 1px solid #333;
            display: flex;
            flex-direction: column;
        }

        .editor textarea {
            width: 100%;
            height: 100%;
            background-color: #1e1e1e;
            color: #cccccc;
            border: none;
            resize: none;
            font-family: 'Courier New', Courier, monospace;
            font-size: 1rem;
            outline: none;
        }

        .error {
            color: #e74c3c;
            margin-top: 10px;
            font-size: 0.9rem;
            display: none;
        }

        .preview {
            background-color: #2d2d2d;
            overflow: hidden;
        }

        /* Scrollbar styling for WebKit */
        ::-webkit-scrollbar {
            width: 8px;
            height: 8px;
        }

        ::-webkit-scrollbar-track {
            background: #1e1e1e;
        }

        ::-webkit-scrollbar-thumb {
            background-color: #555;
            border-radius: 4px;
        }

        /* Responsive Design */
        @media (max-width: 768px) {
            .container {
                flex-direction: column;
            }
            .editor, .preview {
                flex: 1; /* Allow flex items to grow */
                display: none; /* Hide both by default */
                height: 100%; /* Ensure they can take full height when displayed */
            }
            .editor.active, .preview.active {
                display: flex;
                flex-direction: column;
            }
            .editor {
                border-right: none;
                border-bottom: 1px solid #333;
            }
            .tabs {
                display: flex;
            }
            .error {
                display: block;
            }
        }
    </style>
</head>
<body>
    <header>
        <div>NoirCode Studio</div>
        <div class="tabs">
            <button id="tab-editor" class="active">Editor</button>
            <button id="tab-preview">Preview</button>
        </div>
    </header>
    <div class="container">
        <div class="editor active">
            <textarea id="code" placeholder="Type your custom code here...">
h1{Welcome to NoirCode Studio}

p{NoirCode Studio is a powerful and intuitive editor designed for NoirCode, a streamlined markup language that enhances HTML development.}

h2{Features}

ul>li{Real-time preview}+li{Error detection}+li{Sleek design}

h2{Getting Started}

p{Begin by typing your NoirCode in the editor. Use the preview pane to see the rendered HTML instantly. NoirCode Studio supports advanced functionalities like nesting elements, adding attributes, and repeating elements efficiently.}
            </textarea>
            <div id="error-message" class="error"></div>
        </div>
        <div class="preview">
            <iframe id="previewFrame" srcdoc="" frameborder="0" style="width: 100%; height: 100%; background-color: transparent;"></iframe>
        </div>
    </div>

    <script>
        const textarea = document.getElementById('code');
        const previewFrame = document.getElementById('previewFrame');
        const errorMessage = document.getElementById('error-message');

        /**
         * Compiler Function:
         * Transforms custom syntax into standard HTML.
         * Supports:
         * - Tag definitions (e.g., h1{Hello})
         * - Attributes and IDs (e.g., button[role="button"]#click-me{Click Me})
         * - Nesting with '>' (e.g., div>p{Text})
         * - Sibling with '+' (e.g., h1{Title}+p{Subtitle})
         * - Repetition with '*' (e.g., p{&index;. Hey}*5)
         * - Embedding CSS and JS using style\{ ... \} and script[...] \{ ... \}
         */
        function compileToHTML(customCode) {
            const lines = customCode.split('\n');
            let html = '';
            let stack = [];
            let errors = [];
            let i = 0;
            const totalLines = lines.length;

            // State machine for block parsing
            let inBlock = false;
            let blockType = ''; // 'style' or 'script'
            let blockAttributes = '';
            let blockContent = '';
            let blockStartLine = 0;

            while (i < totalLines) {
                let line = lines[i].trim();

                // Skip empty lines
                if (line === '') {
                    i++;
                    continue;
                }

                if (inBlock) {
                    // Check for block end
                    if (line === '\\}') {
                        // Embed the block content
                        if (blockType === 'style' || blockType === 'script') {
                            html += `<${blockType}${blockAttributes}>\n${blockContent}</${blockType}>\n`;
                        } else {
                            // Treat as normal tag if block type is unknown
                            html += `<${blockType}${blockAttributes}>\n${blockContent}</${blockType}>\n`;
                        }
                        // Reset block state
                        inBlock = false;
                        blockType = '';
                        blockAttributes = '';
                        blockContent = '';
                        blockStartLine = 0;
                        i++;
                        continue;
                    } else {
                        // Append to block content
                        blockContent += line + '\n';
                        i++;
                        continue;
                    }
                }

                // Check for block start
                const blockStartMatch = line.match(/^(style|\w+)(\[[^\]]+\])?\\\\\{$/);

                // Corrected regex: need to escape backslash in JavaScript string
                const correctedBlockStartMatch = line.match(/^(style|\w+)(\[[^\]]+\])?\\\{$/);

                if (correctedBlockStartMatch) {
                    inBlock = true;
                    blockType = correctedBlockStartMatch[1];
                    blockAttributes = correctedBlockStartMatch[2] ? replaceIndexPlaceholders(correctedBlockStartMatch[2].slice(1, -1), 0) : '';
                    blockStartLine = i + 1; // For error reporting if block not closed
                    i++;
                    continue;
                }

                // Handle sibling elements using '+'
                const siblingTokens = splitRespectingBlocks(line, '+');
                siblingTokens.forEach(token => {
                    // Handle nesting with '>'
                    const nestingTokens = splitRespectingBlocks(token, '>');
                    let currentParentTags = [...stack]; // Clone the current stack for nesting

                    nestingTokens.forEach((nestedToken, index) => {
                        nestedToken = nestedToken.trim();
                        const isLast = index === nestingTokens.length - 1;

                        if (nestedToken === '') {
                            // Skip empty tokens to prevent errors
                            return;
                        }

                        try {
                            const { tag, attributes, id, content, repeat } = parseElement(nestedToken, i + 1);

                            let attrString = '';
                            if (attributes) attrString += attributes;
                            if (id) attrString += ` id="${id}"`;

                            if (repeat > 1) {
                                for (let j = 1; j <= repeat; j++) {
                                    // Replace &index; in content
                                    let finalContent = replaceIndexPlaceholders(content, j);

                                    // Replace &index; in attributes and id
                                    let finalAttributes = replaceIndexPlaceholders(attributes, j);
                                    let finalId = replaceIndexPlaceholders(id, j);

                                    let finalAttrString = '';
                                    if (finalAttributes) finalAttrString += finalAttributes;
                                    if (finalId) finalAttrString += ` id="${finalId}"`;

                                    if (isLast) {
                                        html += `<${tag}${finalAttrString}>${finalContent}</${tag}>\n`;
                                    } else {
                                        html += `<${tag}${finalAttrString}>\n`;
                                        stack.push(tag);
                                    }
                                }
                            } else {
                                if (isLast) {
                                    if (content) {
                                        let finalContent = replaceIndexPlaceholders(content, 0);
                                        html += `<${tag}${attrString}>${finalContent}</${tag}>\n`;
                                    } else {
                                        html += `<${tag}${attrString}></${tag}>\n`;
                                    }
                                } else {
                                    html += `<${tag}${attrString}>\n`;
                                    stack.push(tag);
                                }
                            }
                        } catch (err) {
                            errors.push(`Line ${err.line}: ${err.message}`);
                        }
                    });
                });

                i++;
            }

            // After processing all lines, check if any blocks are still open
            if (inBlock) {
                errors.push(`Block starting at line ${blockStartLine} for <${blockType}> not closed with '\\}'.`);
            }

            // Close any remaining open tags
            while (stack.length > 0) {
                const tag = stack.pop();
                html += `</${tag}>\n`;
            }

            if (errors.length > 0) {
                return { html: '', errors };
            }

            return { html, errors: [] };
        }

        /**
         * Splits a string by a delimiter but ignores delimiters inside quotes or blocks.
         * @param {string} str - The string to split.
         * @param {string} delimiter - The delimiter to split by.
         * @returns {Array} - Array of split tokens.
         */
        function splitRespectingBlocks(str, delimiter) {
            const tokens = [];
            let current = '';
            let inQuotes = false;
            let quoteChar = '';
            let escape = false;

            for (let char of str) {
                if (escape) {
                    current += char;
                    escape = false;
                    continue;
                }

                if (char === '\\') {
                    current += char;
                    escape = true;
                    continue;
                }

                if ((char === '"' || char === "'") && !inQuotes) {
                    inQuotes = true;
                    quoteChar = char;
                    current += char;
                    continue;
                }

                if (char === quoteChar && inQuotes) {
                    inQuotes = false;
                    quoteChar = '';
                    current += char;
                    continue;
                }

                if (!inQuotes && char === delimiter) {
                    tokens.push(current);
                    current = '';
                    continue;
                }

                current += char;
            }

            if (current !== '') {
                tokens.push(current);
            }

            return tokens;
        }

        /**
         * Replaces all instances of &index; with the provided index number.
         * If index is 0, it leaves the placeholder as is (useful for non-repetitive cases).
         * @param {string} str - The string to process.
         * @param {number} index - The index to replace &index; with.
         * @returns {string} - The processed string.
         */
        function replaceIndexPlaceholders(str, index) {
            if (index > 0) {
                return str.replace(/&index;/g, index);
            }
            return str;
        }

        /**
         * Parses an element definition from the custom syntax.
         * @param {string} token - A token from the custom code.
         * @param {number} lineNumber - The line number for error reporting.
         * @returns {Object} - Parsed element details.
         */
        function parseElement(token, lineNumber) {
            // Regex to match the element definition with optional attributes, ID, content, and repetition
            // Example matches:
            // div>p[title="button"]#click-me{Click Me}*5
            const regex = /^(\w+)(\[[^\]]+\])?(#[\w\-]+)?(\{[^}]*\})?(\*\d+)?$/;
            const match = token.match(regex);

            if (!match) {
                throw { message: `Invalid syntax near "${token}".`, line: lineNumber };
            }

            const [ , tag, attrs, id, content, repeat ] = match;
            let attributes = '';

            if (attrs) {
                // Remove the surrounding brackets
                const attrContent = attrs.slice(1, -1);
                // Replace &index; if any
                const replacedAttrContent = replaceIndexPlaceholders(attrContent, 0);
                // Validate attribute format
                const attrRegex = /(\w+)="([^"]+)"/g;
                let attrMatch;
                while ((attrMatch = attrRegex.exec(replacedAttrContent)) !== null) {
                    const [ , attrName, attrValue ] = attrMatch;
                    attributes += ` ${attrName}="${attrValue}"`;
                }

                // Check if attributes are correctly formatted
                const validAttrFormat = /^[\w\s-]+="[^"]+"$/.test(replacedAttrContent.replace(attrRegex, '').trim()) === false;
                // If attributes are present but no valid attributes were parsed
                if (attributes.trim() === '' && attrContent.trim() !== '') {
                    throw { message: `Attributes must be in the format key="value".`, line: lineNumber };
                }
            }

            const element = {
                tag: tag,
                attributes: attributes,
                id: id ? id.slice(1) : '', // Remove '#' from id
                content: content ? content.slice(1, -1) : '',
                repeat: repeat ? parseInt(repeat.slice(1)) : 1
            };

            return element;
        }

        /**
         * Updates the preview iframe based on the compiled HTML.
         */
        function updatePreview() {
            const customCode = textarea.value;
            let compilationResult;
            try {
                compilationResult = compileToHTML(customCode);
            } catch (error) {
                compilationResult = { html: '', errors: [`Unexpected error: ${error.message}`] };
            }

            const { html, errors } = compilationResult;

            if (errors && errors.length > 0) {
                errorMessage.textContent = errors.join(' | ');
                errorMessage.style.display = 'block';
                previewFrame.srcdoc = ''; // Clear preview if there are errors
            } else {
                errorMessage.textContent = '';
                errorMessage.style.display = 'none';
                // Wrap with basic HTML structure and custom dark theme
                const fullHTML = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Preview</title>
    <style>
        body {
            background-color: #1e1e1e;
            color: #cccccc;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
        }
        h1, h2, h3, h4, h5, h6 {
            color: #ffffff;
        }
        p {
            color: #dcdcdc;
            margin-bottom: 10px;
        }
        button {
            padding: 10px 20px;
            background-color: #3498db;
            color: #fff;
            border: none;
            cursor: pointer;
            border-radius: 4px;
            margin-top: 10px;
        }
        button:hover {
            background-color: #2980b9;
        }
        a {
            color: #9b59b6;
        }
        a:hover {
            color: #8e44ad;
        }
        /* Additional styles for various elements */
        ul {
            list-style-type: disc;
            padding-left: 20px;
            margin-bottom: 10px;
        }
        li {
            margin-bottom: 5px;
        }
        input, textarea {
            background-color: #333333;
            color: #ffffff;
            border: 1px solid #555555;
            padding: 8px;
            border-radius: 4px;
            margin-top: 5px;
        }
        input:focus, textarea:focus {
            border-color: #3498db;
            outline: none;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
        }
        th, td {
            border: 1px solid #555555;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #444444;
        }
        tr:nth-child(even) {
            background-color: #2d2d2d;
        }
        /* Embedded Styles */
        ${extractEmbeddedStyles(html)}
    </style>
</head>
<body>
${html}
</body>
</html>`;
                previewFrame.srcdoc = fullHTML;
            }
        }

        /**
         * Extracts embedded <style> blocks from the generated HTML to include in the preview's head.
         * @param {string} html - The generated HTML content.
         * @returns {string} - Extracted CSS from <style> blocks.
         */
        function extractEmbeddedStyles(html) {
            const styleRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
            let styles = '';
            let match;
            while ((match = styleRegex.exec(html)) !== null) {
                styles += match[1] + '\n';
            }
            return styles;
        }

        // Initialize preview
        updatePreview();

        // Update preview on input with a slight debounce
        let timeout;
        textarea.addEventListener('input', () => {
            clearTimeout(timeout);
            timeout = setTimeout(updatePreview, 300);
        });

        // Tab functionality for mobile
        const tabEditor = document.getElementById('tab-editor');
        const tabPreview = document.getElementById('tab-preview');
        const editor = document.querySelector('.editor');
        const preview = document.querySelector('.preview');

        function activateTab(tab) {
            if (tab === 'editor') {
                tabEditor.classList.add('active');
                tabPreview.classList.remove('active');
                editor.classList.add('active');
                preview.classList.remove('active');
            } else if (tab === 'preview') {
                tabPreview.classList.add('active');
                tabEditor.classList.remove('active');
                preview.classList.add('active');
                editor.classList.remove('active');
            }
        }

        tabEditor.addEventListener('click', () => activateTab('editor'));
        tabPreview.addEventListener('click', () => activateTab('preview'));
    </script>
</body>
</html>

---

Example usage:

ul\{
  li{Real-time preview}\n
  li{Error detection}\n
  li{Sleek design}
\}

---

It currently doesn't support this feature, so I hope you plan it and implement it to be functional and working properly without any errors