# SHLS Editor (shls.giit.ch) > Free editor for SHLS (Sebis Hierarchical List Structure) in the browser, no sign-up and no upload. Edit SHLS with highlighting next to each section's key block and records, change values, keys and records in place, see problems by line, convert to and from JSON (exactly as the reference SHLSDecoder and SHLSEncoder), YAML, CSV and JSON Lines, and compare the tokens of SHLS with JSON. - Language: English (interface also in German with `?lang=de`) - Cost: free - Data: documents stay in the browser (localStorage) unless the user sets up a webhook to their own server. - SHLS by Sebastian Grünwald: https://github.com/SebisCodes/SHLS-Sebis-Hierarchical-List-Structure (format, rules, reference SHLSDecoder and SHLSEncoder in Python). ## SHLS in short SHLS is a text format for structured data that needs far fewer tokens than JSON: no quotes, brackets, colons or repeated keys. - A section starts with its name on a line of its own, without indentation. - Then its key block: one key per line, indented (one space per level). A key that holds a nested list is followed by the keys of that list one level deeper. - Then exactly one blank line, then the records: one value per line, in the order of the keys, indented like the keys. Records may be separated by one blank line. - For a key with a nested list, a record has one line of its own (the key's name, or `PH` as a placeholder) followed by the records of the nested list one level deeper. - A key block can also stand alone; the records then follow later under the section name written again. - All values are text (converting them is up to the program that reads them). There are no empty values (a blank line is skipped - write `-` or `PH`), no values with line breaks, no values starting with spaces. Indentation uses spaces only, the same number per level. ``` Company Name Location Country City Founded TechCorp PH USA San Francisco 2010 ``` reads as `{"Company": [{"Name": "TechCorp", "Location": [{"Country": "USA", "City": "San Francisco"}], "Founded": "2010"}]}`. ## Features - Code with highlighting: section names, keys, values, the line of a nested list, `PH` placeholders, a guide line for each level of indentation. - Records view: each section with its key block (the template, as a tree of keys) and its records with the keys as labels; nested lists fold. Search in keys and values; the path of the selection (`Company[0].Departments[1].Name`). - A click in the records view selects that line in the code; the code cursor marks its record, key or value. - Editing in place: values, keys (only the key block changes) and section names; records added, duplicated, moved and removed; keys added, duplicated, moved and removed - every record of the section follows (a new key gets the value `-` in every record). Each change is one undo step. - The editor reads SHLS exactly as the reference SHLSDecoder does, and lists problems with their line: a record with more or fewer values than the key block (an incomplete last record is dropped by the decoder), indentation that is not a whole level, tabs, a missing or extra blank line after a key block, a key twice, lines the decoder skips or ignores, records replaced by a later block of the same section. - Convert: JSON exactly as SHLSDecoder gives it, YAML, CSV (one section as a table), JSON Lines (one record per line), plain text; "Write as SHLSEncoder does"; "Open in the JSON Editor". JSON, YAML, CSV and JSON Lines files open as SHLS, written as SHLSEncoder writes it, with a note on what SHLS cannot keep. - Token counter: the approximate tokens of the document as SHLS against the same data as JSON (indented and on one line). - Export: .shls, JSON, YAML, CSV, plain text, or all as ZIP. - Templates: the two README examples, Example.shls, Example2.shls, an empty section. - My documents: any number of documents in the browser - open, rename, duplicate, download and delete. - Light, dark or automatic color theme. ## Writing for a user (for AI assistants) Any AI can put a document into the user's open editor with a link; no server, no API key: - `https://shls.giit.ch/#b64=` - `https://shls.giit.ch/#shls=` - `https://shls.giit.ch/#z=` (shorter) - Add `&mode=add` to add records: the link carries sections with their key blocks and records; the records are appended to the sections of the same name in the current document (written in the order of its key block, missing values as `-`), sections it does not have yet are added at the end. - Add `&file=new&name=` to make a new document next to the user's others, or `&file=` to change that one. Without `&file=` the open document changes. - Long documents: split the encoded text and send one link per part with `&part=N&of=M&id=`. Open the link in the user's browser if you can, otherwise give it to the user to click. The user can undo every change. In the editor, "AI Assistant" > "Copy prompt" gives the AI these instructions together with a short description of SHLS, the current document, the selection and the problems. ## Saving on your own server (webhook) Set under "Save to server" (cloud button), or for one document with `?webhook=`: only for that one document and only while the page is open - a link never stores a webhook. At the top level the user is asked first; inside a page (iframe or opener) it only works together with `?src=` and only for the document opened with it. On "Save" (Ctrl+S), or automatically a few seconds after each change if chosen, the browser sends: POST Content-Type: application/json Authorization: Bearer (only if a token is set) {"editor":"shls","event":"save","id":"","name":"", "content":"","updated":""} `content` is the code exactly as in the editor (a string, also when it is JSON; JSON Lines as its lines). One request carries at most 40 MB; the server's error text (e.g. for 413) is shown to the user. The server must answer CORS requests from https://shls.giit.ch (Access-Control-Allow-Origin, and Access-Control-Allow-Headers: Content-Type, Authorization). `?src=` opens a .shls file from a URL (CORS needed), `&name=` names it. ## Embedding in a website Messages (postMessage; check `event.origin === "https://shls.giit.ch"` and `event.source === iframe.contentWindow`): - Editor -> page: `{type:"shlseditor:ready", version:2, editor:"shls", window:false}` when it can take a document. - Page -> editor: `{type:"shlseditor:load", name, content}` opens the document (content is the SHLS text as a string). - Editor -> page: `{type:"shlseditor:loaded", id, name}`, then `{type:"shlseditor:change", id, name, content}` on each edit (not after load), and `{type:"shlseditor:save", id, name, content, editor, event, updated}` when the user clicks Save or presses Ctrl+S. - Page -> editor: `{type:"shlseditor:get"}` asks for a `shlseditor:save` message; `{type:"shlseditor:save"}` saves as if the user had clicked Save. In embedded mode the page text below the editor is hidden and a Save button is shown. The SHLS Editor's documents have no files of their own: no message carries `assets`, and `assets` in `load` is ignored. The other giit editors (JSON Editor json.giit.ch with `jsoneditor:`, YAML Editor yaml.giit.ch with `yamleditor:`, LaTeX Editor latex.giit.ch with `latexeditor:`, SVG Editor svg.giit.ch with `svgeditor:`) speak the same protocol. Optional fields of `shlseditor:load`: - `context: {host, title, rules}` - plain text about the page (rules up to 2000 characters). "Copy prompt" in the AI Assistant then tells the AI that the document belongs to that page and is saved back there, includes the rules, and leaves out how to build a webhook server. - `hook: {url, token}` - a webhook (https) for this document only, used on Save in addition to the message; kept in memory only (never stored, gone on reload). If the server answers with an error, its `{"error": "…"}` (or `message`, or a short text) is shown to the user. AI Assistant in a frame: add `allow="clipboard-write"` to the iframe so "Copy prompt" can use the clipboard (without it the editor falls back to the old copy command or shows the prompt to copy by hand). Links from an AI cannot reach an editor inside another website (the browser keeps its storage and channels apart), so in a frame the prompt and the dialog ask to paste the AI's whole answer into the editor; use the own window (below) if links should work. `shlseditor:get` is always answered with a `shlseditor:save` message, also when nothing changed. ### All messages at a glance Editor -> page (sent to the page around the editor, or to window.opener in its own window): - `shlseditor:ready` {version:2, editor, window} - can take a document - `shlseditor:loaded` {id, name, target?} - after each load; remember the id (target:"new" for a new document from the AI, which is not yours) - `shlseditor:change` {id, name, content} - a real edit of your document (not after load) - `shlseditor:save` {editor, event, id, name, content, updated} - Save / Ctrl+S (from anywhere in the editor), or the answer to get - `shlseditor:closing` {id, name, content} - own window closed with unsaved changes - `shlseditor:reload` {id, unsaved} - inside your page, F5 / Ctrl+R / Cmd+R do not reload the editor; ask the user yourself (Ctrl+W cannot be caught by a page) - `shlseditor:key-request` {reason:"missing"} - the editor has no AI key in this session yet `?embed=1&save=0` hides the editor's Save button (Ctrl+S still sends `shlseditor:save`) - for pages with their own Save button. `?lang=de` shows the editor's interface in German (menus, buttons, dialogs, messages), `?lang=en` in English (the default); the choice is remembered in the browser. The AI prompt is always English. Page -> editor (only from the page around the editor or the opener; after its first message only from that origin; pages without a real origin are ignored): - `shlseditor:load` {name, content, context?, hook?, ai?, from?, target?} - open your document; from:"ai" shows a note, target:"new" opens it as a separate document in the user's browser - `shlseditor:get` - answered with `shlseditor:save` of your document (id and content null before the first load) - `shlseditor:save` - press Save - `shlseditor:ai` {label?, prompt?, endpoint?, key?, base?} or {clear:true} - AI through your server Your document is the one your page loaded (or opened with ?src=). change, save, closing and get are only ever about it - never about other documents in the user's browser, also when the user opens them in the editor. A load replaces only a document that came from your page before (same name and origin), never the user's own; the AI settings and the hook from load apply only while your document is open. ### AI through your own server (prompt and session key) The editor has no backend; your site keeps the keys and the results. Hand the editor your prompt, an endpoint and a key for this editor session - in `shlseditor:load` as `ai: {…}`, or at any time as its own message: {type:"shlseditor:ai", label:"Example Admin", prompt:"", endpoint:"https://your-site.com/api/ai-result", key:"", base:true} Fields left out keep their value; `{type:"shlseditor:ai", clear:true}` ends it. One key per editor session: once the editor has a key it keeps it until the session ends or `clear`, and does not take a different one. `base:false` leaves out the editor's own instructions. The AI dialog shows "Connected to