CUI

Components / Data display

Code editor

An editable code field with syntax highlighting, for shader editors, script consoles and config files.

Functions: cui_code_editor, cui_code_editor_goto

Code editor

Usage

static char src[64 * 1024] = "void main() {\n}\n";   /* yours: edited in place, NUL terminated */

cui_code_editor_result r = cui_code_editor(ui, "shader", src, sizeof src, .lang = "c", .height = 360,
                                           .placeholder = "Write a fragment shader");
if (r.changed) recompile(src);
if (r.refused) cui_toast(ui, "The shader is too long", .tone = CUI_TONE_WARNING);
cui_textf(ui, "Ln %d, Col %d", r.line, r.column);

if (error_line) cui_code_editor_goto(ui, "shader", error_line, error_column);   /* jump to a compile error */

Editable code for shader editors, script consoles and config files, with the code block's highlighting (C, C++, JavaScript, TypeScript, Python, Rust, Go, JSON and shell, or plain text with no lang), its surface and its monospace font. You own the text: a NUL terminated buffer and its capacity, edited in place. An edit that would not fit is refused whole, never cut in half, and the result reports it (refused) so you can say so. The result also gives the caret's line and column (columns count a tab to its stop), the selection as byte offsets, the line count, whether the text changed this frame and, with the find bar open, how many matches there are and which one is selected. A gutter on the left numbers the lines and marks the caret's line, which also gets a quiet band across the editor; the bracket beside the caret and its partner are boxed. Lines never wrap: long ones scroll sideways under the gutter, which stays, and a hairline marks the gutter's edge while the code is scrolled. Only the lines in view are tokenized and drawn, so a file of tens of thousands of lines scrolls and types like a short one. .read_only keeps selection, copy, find and go to line but refuses every edit; .placeholder shows while the text is empty; .tab_size (default 4) and .use_tabs choose how indentation is typed; .height defaults to 320 points and a negative height fills the space. cui_code_editor_goto puts the caret at a line and column, cui_code_editor_select selects bytes and cui_code_editor_find opens the find bar with a query; each focuses the editor and scrolls there on its next frame (call them from the same id scope).

Mouse: click places the caret, Shift+click extends, drag selects (the view scrolls when the pointer leaves it), double-click selects a word, triple-click or a click in the gutter selects a line, and dragging after a double or triple click extends by words or lines. The wheel scrolls, Shift+wheel or a sideways scroll goes sideways, and the thin scrollbars that appear can be dragged. Keys, with the editor focused (on a Mac, Cmd for Ctrl and Option for the word moves):

  • Arrows move; Ctrl+Left and Ctrl+Right move by word; Up and Down keep the column; Page Up and Page Down move by a screen; Home goes to the first character of the line, then to column 0; End to the end of the line; Ctrl+Home and Ctrl+End to the start and end of the text. Shift with any of them extends the selection; Ctrl+A selects everything.
  • Ctrl+C, Ctrl+X and Ctrl+V copy, cut and paste; without a selection, copy and cut take the whole line. Ctrl+Z undoes, Ctrl+Shift+Z or Ctrl+Y redoes; typing within a second is one step, and Enter, paste, cut and indentation are steps of their own.
  • Tab inserts spaces to the next tab stop; with a selection, Tab and Shift+Tab indent and outdent every selected line (Shift+Tab also outdents the caret's line). Backspace in the indentation goes back to the previous stop.
  • Enter starts the new line at this line's indentation, one level deeper after an opening bracket in C-like languages or a colon in Python; between a pair of brackets the closing one moves to a line of its own. A closing brace typed on a blank line steps back a level.
  • Ctrl+F opens the find bar with the selected text: the matches are boxed, Enter and Shift+Enter (or the arrows) go to the next and previous one, wrapping around, and the count shows which one is selected. Case is ignored. Ctrl+G opens go to line (42 or 42:7). Esc closes the bar and returns to the code.
  • Esc in the code closes the find bar, or else clears the selection; with neither, it lets the next Tab move focus out of the editor, since Tab otherwise types.

Keyboard

  • Mouse: click places the caret, Shift+click extends, drag selects (the view scrolls when the pointer leaves it), double-click selects a word, triple-click or a click in the gutter selects a line, and dragging after a double or triple click extends by words or lines.
  • The wheel scrolls, Shift+wheel or a sideways scroll goes sideways, and the thin scrollbars that appear can be dragged.
  • Keys, with the editor focused (on a Mac, Cmd for Ctrl and Option for the word moves):
  • Arrows move; Ctrl+Left and Ctrl+Right move by word; Up and Down keep the column; Page Up and Page Down move by a screen; Home goes to the first character of the line, then to column 0; End to the end of the line; Ctrl+Home and Ctrl+End to the start and end of the text.
  • Shift with any of them extends the selection; Ctrl+A selects everything.
  • Ctrl+C, Ctrl+X and Ctrl+V copy, cut and paste; without a selection, copy and cut take the whole line.
  • Ctrl+Z undoes, Ctrl+Shift+Z or Ctrl+Y redoes; typing within a second is one step, and Enter, paste, cut and indentation are steps of their own.
  • Tab inserts spaces to the next tab stop; with a selection, Tab and Shift+Tab indent and outdent every selected line (Shift+Tab also outdents the caret's line).
  • Backspace in the indentation goes back to the previous stop.
  • Enter starts the new line at this line's indentation, one level deeper after an opening bracket in C-like languages or a colon in Python; between a pair of brackets the closing one moves to a line of its own.
  • Ctrl+F opens the find bar with the selected text: the matches are boxed, Enter and Shift+Enter (or the arrows) go to the next and previous one, wrapping around, and the count shows which one is selected.
  • Ctrl+G opens go to line (42 or 42:7).
  • Esc closes the bar and returns to the code.
  • Esc in the code closes the find bar, or else clears the selection; with neither, it lets the next Tab move focus out of the editor, since Tab otherwise types.

Options of cui_code_editor

OptionTypeDefaultDescription
.langconst char *as cui_code_block: "c", "cpp", "js", "ts", "python", "rust", "go", "json", "shell"; "text" for none
.widthcui_sizefilldefault fill
.heightfloat320default 320; negative fills the space
.sizefloat13font size, default 13
.tab_sizeint4columns per indentation level, default 4
.use_tabsboolindent with tab characters instead of spaces
.read_onlyboolShows the value but does not let it be edited.
.no_line_numbersboolhides the gutter of line numbers
.autofocusboolTakes the keyboard focus when it first appears.
.placeholderconst char *shown while the text is empty
.marksconst cui_text_mark *ranges to highlight (search results, regex matches), sorted by start
.mark_countintnumber of marks

cui_code_editor_result

FieldTypeDescription
changedboolthe text changed this frame
refusedboolan edit did not fit in the capacity and was dropped
focusedboolthe editor or its find bar has the keyboard
cursorintcaret and the other end of the selection, byte offsets
anchorintcaret and the other end of the selection, byte offsets
lineintthe caret, 1 based; columns count tabs to their stop
columnintthe caret, 1 based; columns count tabs to their stop
line_countintlines, and bytes of text
lengthintlines, and bytes of text
bracketintthe bracket beside the caret and its partner, byte offsets, or -1
bracket_matchintthe bracket beside the caret and its partner, byte offsets, or -1
find_matchesintwith the find bar open: matches, and which one is selected (1 based, 0 none)
find_indexintwith the find bar open: matches, and which one is selected (1 based, 0 none)

Related

  • Code block: Read-only source code with syntax highlighting, optional line numbers and a copy button.
  • Toast: A short message that appears in a corner and goes away by itself, with an optional action.
  • Diff viewer: Compares two versions of a text line by line.
  • Markdown view: Renders markdown text as native content: headings, lists, tables, code, task lists and links.