Project Documentation
🚀 1. Overview
Incode: A Built-in IDE for Unity
Project Overview
Incode is an integrated development environment (IDE) designed specifically for Unity, aiming to streamline the scripting and debugging workflow within the Unity Editor. Unlike external IDEs (e.g., Visual Studio, Rider), Incode embeds itself directly into Unity’s UIToolkit framework, providing a native, lightweight, and extensible development environment. The project is still in its early stages, with a phased roadmap outlined in docs/TestShellWorkbenchEvolutionPlan.md, which details plans to evolve the current "TestShell" into a modular, extensible workbench leveraging Unity’s UIToolkit for a modern, performant UI experience.
The core purpose of Incode is to reduce context-switching between Unity’s Inspector, Project Window, and an external IDE by providing a unified interface for scripting, debugging, and asset management. This is particularly valuable for Unity developers who frequently work with DAX (Data Analysis Expressions), a formula language used in Power BI and other Microsoft analytics tools. The inclusion of a DAX syntax highlighter (tm-grammars/Ignored/dax.json) suggests that Incode may also cater to developers working with data-driven applications in Unity, such as those using Unity for data visualization, business intelligence tools, or custom analytics dashboards.
Incode’s architecture appears to be modular, with a focus on extensibility. The presence of a tm-grammars directory (TextMate grammar files) indicates support for syntax highlighting across multiple languages, while the TestShellWorkbenchEvolutionPlan.md hints at a phased approach to integrating additional features like debugging tools, code navigation, and asset management. The project’s long-term vision seems to be transforming Unity’s default scripting workflow into a full-fledged, in-editor IDE experience.
Core Problem & Solution
The primary problem Incode solves is the fragmentation in Unity’s development workflow. Currently, Unity developers rely on external IDEs for scripting, debugging, and asset management, which introduces inefficiencies such as:
- Context-switching overhead (switching between Unity Editor and an external IDE).
- Lack of native Unity integration (e.g., no direct access to Unity’s API documentation, asset database, or scene hierarchy from the IDE).
- Limited real-time debugging (debugging Unity scripts often requires manual log inspection or external tools).
Incode addresses these issues by:
- Embedding an IDE directly into Unity’s UIToolkit, reducing the need for external tools.
- Providing syntax highlighting for DAX and other languages, improving code readability for data-driven applications.
- Enabling modular extensibility, allowing developers to add custom tools (e.g., debugging, asset management) without leaving the Unity Editor.
Tech Stack at a Glance
| Category | Technology | Purpose |
|---|---|---|
| Core Framework | Unity Editor | Host environment for the embedded IDE. |
| UI Framework | Unity UIToolkit | Provides the UI components and layout system for the IDE. |
| Syntax Highlighting | TextMate Grammar (tmLanguage) | Defines syntax rules for DAX and other languages (e.g., dax.json). |
| Scripting | C# | Primary language for Unity development and IDE logic. |
| Planning Docs | Markdown | Documentation for project evolution (e.g., TestShellWorkbenchEvolutionPlan.md). |
| Version Control | Git | Source control for tracking changes and collaboration. |
Future Directions
While Incode is still in its early stages, the roadmap suggests a phased evolution toward a fully modular workbench. Key milestones likely include:
- Phase 1: Basic script editing with syntax highlighting (DAX, C#).
- Phase 2: Debugging integration (breakpoints, variable inspection).
- Phase 3: Asset management (directly browsing/modifying Unity assets).
- Phase 4: Extensibility (plugins for custom tools, language support).
The inclusion of DAX syntax support hints at a niche but growing use case: Unity for data-driven applications (e.g., interactive dashboards, analytics tools). If Incode matures, it could become a compelling alternative to external IDEs for Unity developers, particularly those working in business intelligence, finance, or custom analytics.
Would you like a deeper dive into any specific aspect of the project (e.g., architecture, syntax highlighting, or roadmap)?
📂 2. Project Structure
Directory Structure
The codebase contains the following primary files and directories:
.gitattributes.gitignoreEditor.metaEditor/Core.metaEditor/Core/Commands.metaEditor/Core/Commands/BuiltInCommandIds.csEditor/Core/Commands/BuiltInCommandIds.cs.metaEditor/Core/Commands/CommandRegistry.csEditor/Core/Commands/CommandRegistry.cs.metaEditor/Core/Commands/ContextKeyService.csEditor/Core/Commands/ContextKeyService.cs.metaEditor/Core/Commands/KeybindingService.csEditor/Core/Commands/KeybindingService.cs.metaEditor/Core/Commands/MenuRegistry.csEditor/Core/Commands/MenuRegistry.cs.metaEditor/Core/Configuration.metaEditor/Core/Configuration/BuiltInSettings.csEditor/Core/Configuration/BuiltInSettings.cs.metaEditor/Core/Configuration/PreferenceValueDtos.csEditor/Core/Configuration/PreferenceValueDtos.cs.meta
Generated via local analysis.
🏗️ 3. Architecture & Data Flow
Incode Editor Architecture Deep Dive
1. Deep-Dive Architecture Reasoning
1.1 Overview: A Modular, Extensible IDE Core
The Incode Editor is a C#-based, Unity-integrated IDE designed to provide a modern, extensible, and performant code editing experience within the Unity Editor. It follows a modular architecture, separating concerns into distinct subsystems such as syntax highlighting, language services, commands, configuration, document management, and UI rendering.
The architecture is heavily inspired by VS Code’s design, particularly in its use of:
- Extension-based extensibility
- Language Server Protocol (LSP)-like services
- Event-driven communication via an Event Bus
- State management through services and registries
Despite being a Unity Editor tool, it avoids tight coupling to Unity’s UI system by abstracting UI rendering through UIToolkit, allowing for potential standalone use or portability.
1.2 Core Architectural Principles
| Principle | Description |
|---|---|
| Separation of Concerns | Each subsystem (e.g., syntax, commands, configuration) is isolated into its own namespace and module. |
| Dependency Injection via Registries | Services are registered and resolved via ServiceRegistry, LanguageServiceRegistry, etc., enabling loose coupling. |
| Event-Driven Architecture | The EventBus mediates all inter-module communication, enabling decoupled and reactive design. |
| Extensibility via Contributions | Extensions implement IExtension and contribute functionality via ExtensionContext. |
| Immutable State & Functional Patterns | Many components (e.g., ImmutableScopeStack, PieceTable) use immutable data structures for thread safety and predictable state transitions. |
| Language Server Protocol (LSP) Analogy | Language services (e.g., ILanguageService, IExpressionEvaluator) mimic LSP behavior, enabling rich language features without tight coupling. |
1.3 Module Interactions & Design Patterns
A. Command System (Editor/Core/Commands/)
- Pattern: Command Pattern + Observer
- Key Components:
CommandRegistry: Singleton registry of all commands.KeybindingService: Maps key chords to command IDs.ContextKeyService: Enables conditional command visibility based on editor state.MenuRegistry: Builds UI menus (e.g., File, Edit) dynamically.
- Interaction Flow:
- User presses
Ctrl+S→KeybindingServiceresolves toBuiltInCommandIds.Save. CommandRegistryinvokes the command handler.ContextKeyServicechecks if the command is enabled (e.g., "canSave" context).- If enabled, the command executes (e.g.,
TextDocument.Save()).
- User presses
- Advanced Design:
- Commands are contributed via extensions.
- Uses delegates (
Action<CommandContext>) for execution. - Supports menu contributions via
MenuRegistry.
B. Document & Text Model (Editor/Core/Document/)
- Pattern: Piece Table + Observer + Strategy
- Key Components:
TextDocument: High-level document model.PieceTable: Efficient immutable text buffer (inspired by VS Code).PieceTree: Tree-based indexing for fast line/character lookups.FindReplaceController: Handles search and replace.FoldingController: Manages code folding regions.
- Advanced Design:
PieceTableuses immutable segments to avoid copying large text.- Supports diffing via
IDiffAlgorithm(e.g.,MyersDiffAlgorithm). TextEditrepresents atomic edits (insert/delete/replace).- Event-driven: Fires
TextChangedEvent,SavedEvent, etc.
C. Language Services (Editor/Core/LanguageServices/)
- Pattern: Facade + Strategy + Observer
- Key Components:
ILanguageService: Core interface for language features (completion, diagnostics, hover).LanguageServiceRegistry: Registers language services by file extension.DiagnosticsManager: Aggregates and displays errors/warnings.IGhostTextProvider: Enables inline suggestions (e.g., AI-assisted code).ReflectionEvaluator: Evaluates expressions in context (e.g., for hover tooltips).
- Interaction Flow:
- User opens a
.csfile →LanguageServiceRegistryresolvesCSharpLanguageService. CSharpLanguageServiceregisters completion, definition, and diagnostic providers.- On typing,
TextDocumentfiresTextChangedEvent→DiagnosticsManagertriggers re-analysis. - Results are published via
EventBus→HoverWidget/CompletionWidgetupdate.
- User opens a
- Advanced Design:
- Mimics Language Server Protocol (LSP) but runs in-process.
- Supports async analysis via
Task-based APIs. - Uses cancellation tokens to abort stale requests.
D. Syntax Highlighting (Editor/Core/Syntax/)
- Pattern: Repository + State Machine
- Key Components:
GrammarRegistry: Loads.tmLanguage.jsonfiles (TextMate grammars).LexerManager: Manages lexers per language.RegexLexer,IDocumentLexer: Tokenize text using regex or line-by-line.TokenState: Tracks lexer state (e.g., in a string, comment, or code).
- Advanced Design:
- Uses Oniguruma regex engine (via
Onigwrap) for high-performance pattern matching. - Supports stateful lexing (e.g., tracking scope in nested structures).
- Tokens are immutable and cached for performance.
- Themes are applied via
ThemeManager(maps token types to colors).
- Uses Oniguruma regex engine (via
E. Configuration & Preferences (Editor/Core/Configuration/)
- Pattern: Registry + Strategy
- Key Components:
PreferencesService: Centralized settings store.SettingsRegistry: Registers settings (e.g.,fontSize,theme).SettingScope: Supports global, workspace, and user-level settings.PreferenceValueDtos: Strongly typed settings.
- Advanced Design:
- Uses decorator pattern (
SettingDescriptor) to define settings. - Supports live reload of settings.
- Settings are serialized to JSON and persisted.
- Uses decorator pattern (
F. Event Bus & Main Thread Dispatcher (Editor/Core/Events/)
- Pattern: Observer + Mediator
- Key Components:
EventBus: Pub-sub system for inter-module communication.MainThreadDispatcher: Ensures UI updates happen on the main thread.
- Advanced Design:
- Events are strongly typed (e.g.,
TextChangedEvent,ThemeChangedEvent). - Uses C# events under the hood but abstracted via
EventBus. - Prevents race conditions by enforcing main-thread execution for UI updates.
- Events are strongly typed (e.g.,
G. Extensions System (Editor/Core/Extensions/)
- Pattern: Plugin Architecture + Context Passing
- Key Components:
IExtension: Base interface for extensions.ExtensionHost: Loads and manages extensions.ExtensionContext: Provides access to services (e.g.,CommandRegistry,LanguageServiceRegistry).
- Advanced Design:
- Extensions are discoverable via
*.incode.*assemblies. - Can contribute commands, language services, grammars, themes.
- Example:
incode.csharpextension registers C# language features and Roslyn-based analysis.
- Extensions are discoverable via
H. UI System (Editor/UI/)
- Pattern: MVVM + Pooling + Dynamic Rendering
- Key Components:
CodeEditorView: Main editor UI.CompletionWidget,HoverWidget: Floating UI elements.DynamicScrollView: Virtualized rendering for performance.Pool<T>: Object pooling for UI elements (e.g., lines, tokens).
- Advanced Design:
- Uses UIToolkit (Unity’s retained-mode UI system).
- Virtualization: Only renders visible lines.
- Dirty tracking: Only updates changed UI elements.
- Theme-aware: Applies colors from
ThemeManager.
1.4 Integration with Unity Editor
- The editor is embedded in Unity via
IncodeEditorWindow. - Uses Unity’s Assembly Definition Files (asmdef) to isolate dependencies.
- Editor-only code (no runtime impact).
- Threading: Heavy computation (e.g., lexing, diagnostics) happens on background threads, with results marshaled to the main thread via
MainThreadDispatcher.
1.5 Advanced Patterns & Techniques
| Pattern/Technique | Usage |
|---|---|
| Immutable Data Structures | PieceTable, ImmutableScopeStack, Token |
| Object Pooling | Pool<T> for UI elements and tokens |
| Strategy Pattern | IDiffAlgorithm, ILanguageService |
| Facade Pattern | TextDocument hides complexity of PieceTable |
| Observer Pattern | EventBus for decoupled communication |
| Registry Pattern | CommandRegistry, LanguageServiceRegistry |
| State Pattern | TokenState for lexer state |
| Dependency Injection | Services are resolved via registries |
| Cancellation & Async | Stale requests are cancelled |
| Virtualization | Only visible lines are rendered |
2. Data Flow & State Transitions
| Origin | Action | Logic Handler | Resulting State |
|---|---|---|---|
| User | Presses Ctrl+S | KeybindingService → CommandRegistry | Command Save is triggered |
CommandRegistry | Executes Save command | TextDocument.Save() | Document is saved to disk |
TextDocument | Fires TextChangedEvent | EventBus | Subscribers (e.g., DiagnosticsManager) are notified |
DiagnosticsManager | Re-analyzes document | CSharpLanguageService (Roslyn) | Diagnostics are updated |
DiagnosticsManager | Publishes DiagnosticsUpdatedEvent | EventBus | ProblemsPanel updates UI |
| User | Types in editor | TextDocument → PieceTable | Text buffer is updated immutably |
PieceTable | Fires TextChangedEvent | EventBus | LexerManager is triggered |
LexerManager | Tokenizes text | RegexLexer (Oniguruma) | Tokens are generated and cached |
LexerManager | Publishes TokensUpdatedEvent | EventBus | SyntaxHighlighter updates UI |
| User | Hovers over symbol | HoverWidget requests info | CSharpLanguageService provides hover text |
CSharpLanguageService | Evaluates symbol | ReflectionEvaluator | Hover tooltip is displayed |
| User | Changes theme | ThemeManager loads new theme | UI colors are updated |
ThemeManager | Publishes ThemeChangedEvent | EventBus | All UI elements re-render with new theme |
| Extension | Registers command | ExtensionContext.RegisterCommand() | Command is added to CommandRegistry |
| Extension | Registers language service | ExtensionContext.RegisterLanguageService() | Language features are enabled for .cs files |
PreferencesService | Saves setting | SettingsRegistry → JSON file | Setting persists across sessions |
3. Mermaid.js Architecture Diagram
4. Summary: Why This Architecture Works
- Modularity: Each subsystem is self-contained and testable.
- Extensibility: New languages, commands, and themes can be added without modifying core code.
- Performance: Immutability, pooling, and virtualization minimize overhead.
- Maintainability: Clear separation of concerns and strong typing reduce bugs.
- Unity Integration: Runs as an editor tool without runtime impact.
This architecture positions Incode as a modern, extensible IDE core that could even be adapted for standalone use outside Unity.
📈 System Architecture Diagram
🛠️ 4. Function Breakdowns
Core Functionality
Based on the file tree, this project implements logic across 9 key source files including README.md, Editor/Core/Syntax/tm-grammars/Ignored/dax.json, Editor/Core/Syntax/tm-grammars/Ignored/cobol.json.
Generated via local analysis.