Runestone Documentation

repository·main·Indexed 25 days ago

https://github.com/simonbs/runestone

A high-performance plain text editor framework for iOS featuring advanced code editing capabilities. It utilizes GitHub's Tree-sitter for incremental parsing to provide syntax highlighting, line numbers, and language-aware indentation. The framework includes support for custom themes via the Theme protocol, regular expression search, and a StringSyntaxHighlighter for generating attributed strings.

Tokens
4.8K
Snippets
10
Records
35
Agent score
84%

What's inside Runestone

  1. Overview of Runestone features

    main

    Runestone is a performant plain text editor for iOS designed with code editing features. It utilizes GitHub's Tree-sitter for incremental parsing to provide syntax highlighting and other code-aware features.

    Key features include:

    • Syntax highlighting and line numbers.
    • Highlighting selected lines and text ranges.
    • Displaying invisible characters (tabs, spaces, line breaks).
    • Character pair insertion (e.g., matching quotes).
    • Customization of fonts, colors, and line height.
    • Line wrapping toggling.
    • Regular expression search.
    • Automatic detection of indentation (spaces vs tabs) and line endings (CR, LF, CRLF).
    • Vertical and horizontal overscroll support.
  2. Available themes in the Runestone example project

    main

    The Runestone example project includes several pre-defined themes for text editing. These themes are used to customize the visual appearance of the editor. The included themes are:

    • One Dark
    • Plain Text
    • Tomorrow
    • Tomorrow Night

    All themes rely on the RunestoneThemeCommon package, which provides the core types used across all theme implementations and the example project.

  3. Add a Tree-sitter language manually

    main

    If you are not using the TreeSitterLanguages package, you can manually add a Tree-sitter parser to your project.

    1. Required Files

    You must include the following files from the parser repository:

    • src/parser.c
    • src/tree_sitter/parser.h
    • queries/highlights.scm

    2. Define the C Function

    A Tree-sitter parser is exposed as a C function named tree_sitter_{language} (e.g., tree_sitter_json). To make this available in Swift, create a header file and import it into your bridging header with the following content:

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    typedef struct TSLanguage TSLanguage;
    
    // Replace {language} with the name of the parser you are importing.
    const TSLanguage *tree_sitter_{language}(void);
    
    #ifdef __cplusplus
    }
    #endif
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    typedef struct TSLanguage TSLanguage;
    
    // Replace {language} with the name of the parser you are importing.
    const TSLanguage *tree_sitter_{language}(void);
    
    #ifdef __cplusplus
    }
    #endif
  4. Clone the Runestone repository for development

    main

    If you are contributing to Runestone or building from source, you must clone the repository with submodules enabled because Runestone depends on Tree-sitter via a submodule. Use the --recursive flag to ensure all dependencies are included.

    git clone --recursive git@github.com:simonbs/Runestone.git
  5. Add a Tree-sitter language using TreeSitterLanguages Swift Package

    main

    The easiest way to add syntax highlighting for a language is to use the TreeSitterLanguages Swift package. This package provides pre-configured bindings for all languages supported by the Runestone Text Editor.

    To use this method, you should add the following packages to your project:

    1. TreeSitter{Language}Runestone: This is the primary package you need to add for a specific language (e.g., TreeSitterJavaScriptRunestone). It automatically includes the necessary C parser code and query files.
    2. TreeSitterLanguagesCommon: This package contains the core basics required for any language integration.

    Note: The TreeSitter{Language}Runestone package depends on TreeSitter{Language} (the C code) and TreeSitter{Language}Queries (the highlighting queries).

  6. Set TextView state using TextViewState

    main

    To avoid blocking the main thread, do not set the language or text directly on the TextView instance, as these are expensive operations. Instead, create a TextViewState object on a background queue and apply it to the text view on the main thread using setState(_:addUndoAction:).

    DispatchQueue.global(qos: .userInitiated).async {
        // Initialize TextViewState on a background queue to avoid blocking the main thread.
        let text = "let foo = \"Hello World\""
        let state = TextViewState(text: text, theme: ColorfulTheme(), language: .javaScript)
        
        DispatchQueue.main.async {
            // setState(_:) must be called on the main thread.
            textView.setState(state)
        }
    }