mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-12 12:12:10 +00:00
added a line number column that syncs to content and scroll
This commit is contained in:
parent
eed11fd9c6
commit
6c3906b04c
@ -1 +1,4 @@
|
||||
<div @ref="this.editorElement" class="code-editor @this.Class" style="@this.CodeEditorThemeStyle"></div>
|
||||
<div class="code-editor @this.Class" style="@this.CodeEditorThemeStyle">
|
||||
<div @ref="this.lineNumbersElement" class="code-editor-line-numbers" aria-hidden="true"></div>
|
||||
<div @ref="this.editorElement" class="code-editor-input"></div>
|
||||
</div>
|
||||
|
||||
@ -23,8 +23,9 @@ public partial class CodeEditor : ComponentBase, IAsyncDisposable
|
||||
public string Class { get; set; } = string.Empty;
|
||||
|
||||
private readonly string editorId = $"code-editor-{Guid.NewGuid():N}";
|
||||
private const string CODE_EDITOR_MODULE = "./system/CodeEditor/code-editor.js?v=20260707-3";
|
||||
private const string CODE_EDITOR_MODULE = "./system/CodeEditor/code-editor.js?v=20260708-1";
|
||||
private ElementReference editorElement;
|
||||
private ElementReference lineNumbersElement;
|
||||
private IJSObjectReference? module;
|
||||
private string CodeEditorThemeStyle => this.GetCodeEditorThemeStyle();
|
||||
|
||||
@ -34,7 +35,7 @@ public partial class CodeEditor : ComponentBase, IAsyncDisposable
|
||||
return;
|
||||
|
||||
this.module = await this.JsRuntime.InvokeAsync<IJSObjectReference>("import", CODE_EDITOR_MODULE);
|
||||
await this.module.InvokeVoidAsync("init", this.editorId, this.editorElement, this.Value, this.Language.ToString());
|
||||
await this.module.InvokeVoidAsync("init", this.editorId, this.editorElement, this.lineNumbersElement, this.Value, this.Language.ToString());
|
||||
}
|
||||
|
||||
public async ValueTask<string> GetCodeAsync()
|
||||
|
||||
@ -204,21 +204,45 @@
|
||||
}
|
||||
|
||||
.code-editor {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(2.8rem, auto) minmax(0, 1fr);
|
||||
min-height: 32rem;
|
||||
height: 62vh;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
padding: 0.8rem;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--mw-code-editor-border, rgba(0,0,0,0.11764705882352941));
|
||||
border-radius: 4px;
|
||||
background: var(--mw-code-editor-background, rgba(255,255,255,1));
|
||||
color: var(--mw-code-editor-foreground, rgba(66,66,66,1));
|
||||
caret-color: var(--mw-code-editor-foreground, rgba(66,66,66,1));
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 0.65rem;
|
||||
line-height: 1.45;
|
||||
white-space: pre;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
.code-editor-line-numbers {
|
||||
overflow: hidden;
|
||||
padding: 0.8rem 0.65rem 0.8rem 0.5rem;
|
||||
border-right: 1px solid var(--mw-code-editor-border, rgba(0,0,0,0.11764705882352941));
|
||||
color: var(--mw-code-editor-foreground, rgba(66,66,66,1));
|
||||
opacity: 0.55;
|
||||
text-align: right;
|
||||
white-space: pre;
|
||||
user-select: none;
|
||||
font: inherit;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.code-editor-input {
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0.8rem;
|
||||
color: var(--mw-code-editor-foreground, rgba(66,66,66,1));
|
||||
caret-color: var(--mw-code-editor-foreground, rgba(66,66,66,1));
|
||||
font: inherit;
|
||||
line-height: inherit;
|
||||
tab-size: inherit;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
@ -27,21 +27,25 @@ const LUA_BUILT_INS = new Set([
|
||||
* The highlighter callback receives the editor DOM node. It must write highlighted
|
||||
* HTML back into that node, so every token emitted by our highlighter is HTML-escaped.
|
||||
*/
|
||||
export function init(id, element, code, language) {
|
||||
export function init(id, element, lineNumbersElement, code, language) {
|
||||
const codeJar = CodeJar(element, getHighlighter(language), {
|
||||
tab: ' ',
|
||||
spellcheck: false
|
||||
});
|
||||
const scrollHandler = () => syncLineNumbersScroll(element, lineNumbersElement);
|
||||
|
||||
codeJar.updateCode(code ?? '');
|
||||
editors.set(id, codeJar);
|
||||
updateLineNumbers(lineNumbersElement, codeJar.toString());
|
||||
codeJar.onUpdate(updatedCode => updateLineNumbers(lineNumbersElement, updatedCode));
|
||||
element.addEventListener('scroll', scrollHandler);
|
||||
editors.set(id, { codeJar, element, scrollHandler });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current plain text from a CodeJar instance.
|
||||
*/
|
||||
export function getCode(id) {
|
||||
return editors.get(id)?.toString() ?? '';
|
||||
return editors.get(id)?.codeJar.toString() ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,17 +53,43 @@ export function getCode(id) {
|
||||
* state stays consistent with CodeJar's internal model.
|
||||
*/
|
||||
export function setCode(id, code) {
|
||||
editors.get(id)?.updateCode(code ?? '');
|
||||
const editor = editors.get(id);
|
||||
if (!editor)
|
||||
return;
|
||||
|
||||
editor.codeJar.updateCode(code ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes one editor instance and removes it from the JS-side registry.
|
||||
*/
|
||||
export function destroy(id) {
|
||||
editors.get(id)?.destroy();
|
||||
const editor = editors.get(id);
|
||||
if (!editor)
|
||||
return;
|
||||
|
||||
editor.element.removeEventListener('scroll', editor.scrollHandler);
|
||||
editor.codeJar.destroy();
|
||||
editors.delete(id);
|
||||
}
|
||||
|
||||
function updateLineNumbers(lineNumbersElement, code) {
|
||||
const lineCount = (code.match(/\n/g)?.length ?? 0) + 1;
|
||||
let lineNumbers = '';
|
||||
for (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {
|
||||
if (lineNumber > 1)
|
||||
lineNumbers += '\n';
|
||||
|
||||
lineNumbers += lineNumber;
|
||||
}
|
||||
|
||||
lineNumbersElement.textContent = lineNumbers;
|
||||
}
|
||||
|
||||
function syncLineNumbersScroll(editorElement, lineNumbersElement) {
|
||||
lineNumbersElement.scrollTop = editorElement.scrollTop;
|
||||
}
|
||||
|
||||
function highlightLua(editor) {
|
||||
editor.innerHTML = highlightLuaCode(editor.textContent ?? '');
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user