Skip to content

Latest commit

 

History

History
51 lines (26 loc) · 14.2 KB

theme-editor.md

File metadata and controls

51 lines (26 loc) · 14.2 KB

Theme Editor

Open View → Theme → Open Theme Editor… in TextMate, or run tm-theme-editor from the command line. Applications/ThemeEditor builds ThemeEditor.app, an AppKit helper app embedded in TextMate's app bundle. It runs as a separate process and uses the same installed bundle catalogue, default settings, and editor components as the containing TextMate build. Opening it from TextMate selects the active document’s current theme, including project or file overrides, and the matching preview sample language when available. Unsupported file types retain the previous sample selection. With no active document, it uses the theme for TextMate’s current appearance. If Theme Editor is already open, it selects the requested theme after offering to save or revert any unsaved changes. The theme list and middle controls have fixed widths, and their dividers cannot be dragged. Resizing the window expands or contracts only the preview column. The minimum window size keeps all three columns usable.

Editing

The left pane groups themes from TextMate's bundle catalogue under Light, Dark, and Unspecified, with names sorted within each section. Section headings scroll with the list instead of staying pinned at the top. Select a theme, or use the + button to create one. Right-click a theme for Duplicate, Delete, and Export…; these actions apply to the theme you clicked. Delete asks for confirmation, discards any unsaved changes to that theme, and uses TextMate’s bundle deletion behavior: local theme files move to Trash, while installed themes receive a local deletion override. Deleting an unsaved theme discards its draft. If the last theme is deleted, a new unsaved theme opens. Command-click a theme to edit its name directly in the left pane. Press Return or click elsewhere to finish editing, or press Escape to cancel the rename and restore the previous name. Save persists the new name. New themes are marked “unsaved” until saved.

The middle pane edits Appearance and the selected style rule. The three side-by-side Appearance buttons select Light, Dark, or Unspecified, with exactly one selected at a time. Appearance uses the same semanticClass metadata as TextMate’s theme menu (theme.light.… or theme.dark.…). Unspecified makes the theme available for either appearance. Changing Appearance moves the draft into its new section immediately; Save persists the classification. Existing themes without that metadata remain unspecified, new themes start as Light, and duplicates retain their source’s classification. The category is independent of the background color. Global rules have an empty scope selector. Syntax rules use TextMate scope selectors, such as comment, string, or keyword.control. Rule order and settings that are not exposed by the controls are preserved. Use the + button in the style-rule group to enter a new rule’s name and scope selector in a dialog. Both fields are required. Canceling leaves the draft unchanged. Click the pencil icon to the right of the style-rule selector to view and edit the selected rule’s name and scope selector. Click Apply to update the draft, or Cancel to leave it unchanged. Scoped rules require a nonempty scope selector. The global rule displays its empty scope as read-only because it applies to the whole editor. Save persists the name. Clear the name to display its scope selector, or Global editor style for a global rule. Editing preserves rule order, colors, and fonts; scope changes update the preview immediately. The − button asks for confirmation and names the selected rule; Cancel leaves the draft unchanged.

Click Invert under Appearance to reverse the theme’s lightness: light backgrounds become dark and dark text becomes light. Syntax and gutter colors keep their hues, saturation, and opacity. Light and Dark classifications swap; Unspecified stays Unspecified. Missing global foreground, background, and caret colors become explicit inverted preview colors, while other inherited colors continue to inherit. Fonts, scopes, metadata, and original imported palette swatches are preserved. The preview updates immediately; use Save to keep the result. Click Invert again to restore the color values. Correct invalid highlighted fields before inverting.

Each color uses one compact row, with a clickable swatch on the left and its hex field on the right. Colors accept #RGB, #RGBA, #RRGGBB, or #RRGGBBAA; click the swatch to open the system color panel. The controls and native preview honor the theme’s colorSpaceName: sRGB when declared, otherwise Apple Generic RGB, matching TextMate. Color-picker selections are converted back into that same space before storing their hex values; existing themes are not retagged or recolored. A blank field removes that override and lets the theme engine resolve its fallback. Gutter colors appears when Global editor style is selected, in a rounded control group with subtle inset dividers. Edit the line-number and editor-margin colors directly. An unset gutter color shows its inherited preview color in the swatch, so the color picker starts with that color and opacity; these controls always edit the theme's global gutterSettings.

Font controls in the selected style-rule group use a font-family menu, a typeface menu, and a compact size field. Sizes accept points (such as 14 or 14pt) and relative values (such as 120% or 1.2em), resolving to 4–200 points; clear the size or choose Inherited in the family menu to remove that override. Bold, Italic, Underline, and Strikethrough buttons set explicit formatting. Turning every button off stores plain, suppressing inherited formatting; Inherited beside the buttons removes the style override instead. Existing PostScript font names remain stored unchanged until you choose a replacement. Font overrides are stored in the theme; scoped/project font settings still participate in TextMate's normal rendering rules.

The right pane is an OakDocumentView, including its real OakTextView and gutter, with the bottom status bar hidden. The preview always shows line numbers so gutter colors can be inspected, without changing TextMate’s line-number preference. Use Sample language above the preview to choose from languages with installed TextMate grammars. Available samples include JavaScript, TypeScript, TypeScript / React, Python, Swift, Rust, Go, C, C++, C#, Java, Ruby, PHP, SQL, Bash, HTML, CSS, JSON, and Markdown. Each sample has over 50 lines covering the language’s comments, documentation, strings and escapes, numbers, declarations, control flow, and other syntax. TypeScript / React includes typed props, hooks, event handlers, JSX tags and attributes, fragments, comments, and embedded expressions. HTML includes embedded CSS and JavaScript; Markdown includes emphasis, links, lists, tables, and fenced code. The available scopes and styles depend on the language grammar and theme.

Syntax highlighting uses the corresponding installed TextMate language bundle. Languages without an available grammar are omitted from the dropdown. Reopen Theme Editor after installing a bundle. The last sample language is remembered when still available; otherwise the first supported language is selected. If no supported grammars are installed, the preview uses plain text and explains how to enable highlighting.

Command-click an element in the preview to select its most-specific matching theme rule in the middle pane. Matching uses TextMate’s own scope-selector ranking; later rules win when specificity ties. When no syntax-specific rule matches, the global style is selected. Theme rules can combine, so less-specific rules may still supply other properties. Command-click inspection leaves the caret, sample text, and theme draft unchanged. Correct any invalid highlighted setting before inspecting another rule.

Samples are editable: select text, fold code, or type more examples to inspect their rendering. Invisibles reveals whitespace. Switching samples retains your sample edits for the session and keeps your theme draft, colors, and fonts. Reset Sample restores the selected sample’s bundled text. Sample edits do not change the theme, execute the code, or save a source file.

Importing color palettes

Use File → Import Colors… and select an Adobe Swatch Exchange (.ase) or DTCG (.tokens.json, .json, or .tokens) file to create a new unsaved theme.

For ASE files, RGB, CMYK, Lab, and Gray swatches are converted to sRGB. ASE files do not include color profiles, so CMYK conversion uses the system device CMYK space. The first named group supplies the theme name, or the filename is used when there is no named group. Swatches from all groups are retained in file order, including their names.

DTCG imports read nested color tokens, inherited group types, legacy hex values, and structured sRGB, linear sRGB, and Display P3 colors. Components and alpha are authoritative; optional hex metadata is ignored. Token aliases and local JSON pointers are resolved, with invalid or circular references rejected. Only tokens whose explicit, inherited, or alias-derived type is color become palette swatches. Untyped aliases are followed to determine their type; a missing target or circular alias chain rejects the entire import, even if the token would not otherwise contribute a color. Tokens with other types are omitted from the palette, but their values can still be referenced by color tokens. Descriptions and extension metadata outside token values are ignored. External references, group extensions, and other color spaces require a resolved export in a supported color space. Names use full token paths, sorted naturally for a stable order. For project exports with Light_tokens.json and Dark_tokens.json sets, the matching set’s primary, secondary, tertiary, info, and neutral tokens supply the five initial syntax colors. The matching primary token also supplies a translucent selection color. All color tokens from all sets remain available in the imported palette. Other token files cycle through their sorted colors. DTCG themes use the filename with .tokens.json, .json, or .tokens removed as their initial name.

The starter theme uses a neutral white background with black text, or a black background with white text when the currently selected theme’s Appearance is Dark. Light and Unspecified default to white. For ASE files, five initial syntax rules cycle through the original palette in file order for strings, keywords/storage, constants, entities/support, and comments. Swatch colors are used exactly as imported, without blending or contrast adjustments. The first swatch also supplies a translucent selection color. These are suggested assignments and can be edited normally.

The Imported palette group retains the original swatches. Choose a swatch, choose Foreground, Background, Caret, Selection, or Invisibles, and click Apply to assign it to the currently selected style rule. Original swatches remain unchanged and are retained when saving, duplicating, or exporting the theme. Importing uses the normal Save, Revert Changes, or Cancel flow for an existing changed draft. Canceling the file dialog or choosing an invalid file leaves the current theme unchanged. Saving the imported theme installs it in the local Theme Editor bundle.

Saving, exporting, and discarding changes

Use File → Export Theme… to export the current draft, including valid unsaved edits, as a standalone .tmTheme XML property list. Choose the filename and location in the save dialog. Right-click a theme and choose Export… to export that item's stored property list without selecting it or prompting to save the current draft. Each export assigns a fresh UUID to the exported copy and preserves its other metadata. Installed files, the source theme’s UUID, and the current draft's unsaved state remain unchanged.

Changes update the preview immediately. The editing controls fill the middle pane and scroll when space is limited. When leaving a changed theme, choose Save, Revert Changes, or Cancel. File → Save Theme or Cmd+S also persists the draft using TextMate's bundle item save API. The current theme and style rule stay selected, including when renaming or changing appearance moves the theme within the grouped list. Existing themes retain their UUID and parent bundle; managed or bundled themes receive a local delta override. New and duplicated themes get new UUIDs in a local Theme Editor bundle. TextMate's bundle watcher detects these files and refreshes its theme menu.

Drafts have private preview UUIDs and uncached styles, so editing them does not modify installed theme objects. Switching themes, creating another theme, closing the window, or quitting offers Save, Cancel, and Revert Changes. Revert Changes in that confirmation dialog discards edits to an existing theme and restores its last loaded or saved version. For a new unsaved theme, it removes the draft from the list. Correct invalid highlighted settings before saving or switching rules.

The editor checks source files and the merged bundle catalogue before saving. If another editor has changed the theme, it retains the draft and refuses to overwrite the newer version. Reopen the utility to load external changes. The theme list is loaded at launch; reopen the utility after installing additional bundles.

The utility uses oak::application_t::support() for TextMate's user support directory and the containing app's resources. It does not install its own shell command automatically. Add TextMate.app/Contents/MacOS to PATH or symlink tm-theme-editor into an existing command directory. Symlink invocation resolves the original executable to find the containing app.

Development

Build through make debug so the Swift library and application resources are present. The ThemeEditor CMake target can be built independently for focused compilation, but the embedded executable in the completed app bundle is the supported launch location. TextMate embeds the signed ThemeEditor.app in Contents/Helpers and its tm-theme-editor launcher in Contents/MacOS before signing the outer app. The preview opts out of language servers and Copilot.