Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 68 additions & 17 deletions .github/instructions/disposable.instructions.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,71 @@
---
description: Guidelines for writing code using IDisposable
description: Guidelines for writing code using IDisposable pattern for resource management and lifecycle control
---

Core symbols:
* `IDisposable`
* `dispose(): void` - dispose the object
* `Disposable` (implements `IDisposable`) - base class for disposable objects
* `this._store: DisposableStore`
* `this._register<T extends IDisposable>(t: T): T`
* Try to immediately register created disposables! E.g. `const someDisposable = this._register(new SomeDisposable())`
* `DisposableStore` (implements `IDisposable`)
* `add<T extends IDisposable>(t: T): T`
* `clear()`
* `toDisposable(fn: () => void): IDisposable` - helper to create a disposable from a function

* `MutableDisposable` (implements `IDisposable`)
* `value: IDisposable | undefined`
* `clear()`
* A value that enters a mutable disposable (at least once) will be disposed the latest when the mutable disposable is disposed (or when the value is replaced or cleared).
# IDisposable Pattern Overview

## Purpose

The IDisposable pattern in VS Code provides a standardized way to manage the lifecycle of resources that need explicit cleanup. This includes event listeners, file system watchers, providers, and other resources that could cause memory leaks if not properly disposed. The pattern ensures deterministic cleanup and prevents resource leaks by providing a consistent interface for releasing resources.

## Scope

- **Included**: Resource lifecycle management, event listener cleanup, provider registration/unregistration, memory leak prevention, automatic cleanup through disposal hierarchies
- **Out of scope**: Garbage collection, automatic memory management for regular objects, browser-specific disposal patterns
- **Integration points**: Used throughout VS Code's architecture - base layer, platform services, editor components, workbench contributions, and extensions

## Architecture

### High-Level Design

The disposable pattern follows a hierarchical cleanup model where parent disposables automatically clean up their children. The design uses composition over inheritance, with `DisposableStore` managing collections of disposables and `Disposable` base class providing automatic registration.

```
IDisposable (interface)
├── Disposable (abstract base class)
│ └── _store: DisposableStore
├── DisposableStore (collection manager)
├── MutableDisposable<T> (single mutable value)
├── DisposableMap<K,V> (key-value store)
└── Helper functions (dispose, toDisposable, combinedDisposable)
```

### Key Classes & Interfaces

- **IDisposable**: Core interface with single `dispose(): void` method for resource cleanup
- **Disposable**: Abstract base class that provides `_store` and `_register()` for automatic child management
- **DisposableStore**: Collection manager for multiple disposables with safe add/remove operations
- **MutableDisposable<T>**: Manages a single disposable value that can be replaced, automatically disposing the previous value
- **DisposableMap<K,V>**: Map that manages disposable values and automatically disposes them on replacement or removal

### Key Files

List of all key files and their purposes:

- **`src/vs/base/common/lifecycle.ts`**: Core disposable infrastructure with IDisposable interface, DisposableStore, Disposable base class, MutableDisposable, DisposableMap, and helper functions
- **`src/vs/base/test/common/lifecycle.test.ts`**: Comprehensive tests for disposable pattern including edge cases and error handling
- **`.eslint-plugin-local/code-no-potentially-unsafe-disposables.ts`**: ESLint rule to detect potentially unsafe usage of DisposableStore and MutableDisposable
- **`extensions/*/src/util/dispose.ts`**: Extension-specific disposable utilities that mirror the core pattern for extension development

## Development Guidelines

### Core Principles
- **Always dispose**: Every created disposable must be disposed either explicitly or by registering with a parent
- **Register immediately**: Use `this._register(new SomeDisposable())` pattern to ensure automatic cleanup
- **Hierarchical cleanup**: Parent disposables should clean up their children automatically
- **Error resilience**: Disposal should handle errors gracefully and continue disposing other resources

### Common Patterns
- **Base class usage**: Extend `Disposable` and use `this._register()` for automatic child management
- **Store collections**: Use `DisposableStore` for managing multiple disposables safely
- **Mutable resources**: Use `MutableDisposable<T>` for resources that may change over time
- **Helper creation**: Use `toDisposable(() => { /* cleanup */ })` for simple cleanup functions

### Anti-patterns to Avoid
- **Manual arrays**: Don't use `IDisposable[]` - use `DisposableStore` instead for better error handling
- **Self-registration**: Never register a disposable on itself
- **Double disposal**: DisposableStore handles multiple disposal attempts safely
- **Disposal after disposed**: Adding to a disposed store will leak resources

## Learnings

84 changes: 65 additions & 19 deletions .github/instructions/observables.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,53 @@
description: Guidelines for writing code using observables and deriveds.
---

# Observables System Overview

## Purpose

The observables system provides a reactive programming framework for VS Code, enabling automatic dependency tracking and efficient updates when data changes. It follows patterns similar to MobX but is specifically tailored for VS Code's architecture and performance requirements.

## Scope

- **Included**: Observable values, derived computations, automatic dependency tracking, transaction batching, event-based observables, and reactive autoruns
- **Out of scope**: Direct DOM manipulation, HTTP requests, or async operations (use utility functions for async integration)
- **Integration points**: Disposables system, event system, VS Code services, and extension APIs

## Architecture

### High-Level Design

The observables system uses a **push-pull hybrid approach** with automatic dependency tracking:

1. **Observable Values** store data and notify observers of changes
2. **Derived Observables** compute values lazily based on other observables
3. **Autoruns** execute side effects when dependencies change
4. **Transactions** batch multiple changes to prevent intermediate notifications
5. **Readers** track dependencies automatically during computation

### Key Classes & Interfaces

- **`IObservable<T>`**: Core interface for readable observable values with dependency tracking
- **`ISettableObservable<T>`**: Interface for observable values that can be updated
- **`ObservableValue`**: Implementation for simple observable values with change notification
- **`Derived`**: Implementation for computed observables derived from other observables
- **`AutorunObserver`**: Implementation for reactive side effects that re-run on dependency changes
- **`TransactionImpl`**: Batches multiple observable changes into single notification cycles

### Key Files

- **`src/vs/base/common/observableInternal/index.ts`**: Main facade exposing all observable APIs
- **`src/vs/base/common/observableInternal/base.ts`**: Core interfaces and contracts for the observable system
- **`src/vs/base/common/observableInternal/observables/observableValue.ts`**: Implementation of basic observable values
- **`src/vs/base/common/observableInternal/observables/derived.ts`**: Implementation of computed observables
- **`src/vs/base/common/observableInternal/reactions/autorun.ts`**: Implementation of reactive side effects
- **`src/vs/base/common/observableInternal/transaction.ts`**: Transaction system for batching changes
- **`src/vs/base/common/observableInternal/utils/utils.ts`**: Utility functions for advanced observable patterns

## Development Guidelines

### Basic Usage Pattern

```ts
class MyService extends Disposable {
private _myData1 = observableValue(/* always put `this` here */ this, /* initial value*/ 0);
Expand Down Expand Up @@ -47,26 +94,25 @@ class MyService extends Disposable {
}
```

### Most Important Symbols

Most important symbols:
* `observableValue`
* `disposableObservableValue`
* `derived`
* `autorun`
* `transaction`
* `observableFromEvent`
* `observableSignalFromEvent`
* `observableSignal(...): IObservable<void>` - use `.trigger(tx)` to trigger a change

* `observableValue` - Creates basic observable values
* `disposableObservableValue` - Observable values that auto-dispose their contents
* `derived` - Creates computed observables
* `autorun` - Creates reactive side effects
* `transaction` - Batches multiple changes
* `observableFromEvent` - Creates observables from events
* `observableSignalFromEvent` - Creates signal observables from events
* `observableSignal(...): IObservable<void>` - Use `.trigger(tx)` to trigger a change

* Check src\vs\base\common\observableInternal\index.ts for a list of all observable utitilies
Check `src/vs/base/common/observableInternal/index.ts` for a complete list of all observable utilities.

## Learnings

* Important learnings:
* [1] Avoid glitches
* [2] **Choose the right observable value type:**
* Use `observableValue(owner, initialValue)` for regular values
* Use `disposableObservableValue(owner, initialValue)` when storing disposable values - it automatically disposes the previous value when a new one is set, and disposes the current value when the observable itself is disposed (similar to `MutableDisposable` behavior)
* [3] **Choose the right event observable pattern:**
* Use `observableFromEvent(owner, event, valueComputer)` when you need to track a computed value that changes with the event, and you want updates only when the computed value actually changes
* Use `observableSignalFromEvent(owner, event)` when you need to force re-computation every time the event fires, regardless of value stability. This is important when the computed value might not change but dependent computations need fresh context (e.g., workspace folder changes where the folder array reference might be the same but file path calculations need to be refreshed)
* [1] Avoid glitches
* [2] **Choose the right observable value type:**
* Use `observableValue(owner, initialValue)` for regular values
* Use `disposableObservableValue(owner, initialValue)` when storing disposable values - it automatically disposes the previous value when a new one is set, and disposes the current value when the observable itself is disposed (similar to `MutableDisposable` behavior)
* [3] **Choose the right event observable pattern:**
* Use `observableFromEvent(owner, event, valueComputer)` when you need to track a computed value that changes with the event, and you want updates only when the computed value actually changes
* Use `observableSignalFromEvent(owner, event)` when you need to force re-computation every time the event fires, regardless of value stability. This is important when the computed value might not change but dependent computations need fresh context (e.g., workspace folder changes where the folder array reference might be the same but file path calculations need to be refreshed)
6 changes: 0 additions & 6 deletions .github/instructions/tree-widgets.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ description: Use when asked to consume workbench tree widgets in VS Code.

# Workbench Tree Widgets Overview

**Location**: `src/vs/platform/list/browser/listService.ts`
**Type**: Platform Services
**Layer**: Platform

## Purpose

The Workbench Tree Widgets provide high-level, workbench-integrated tree components that extend the base tree implementations with VS Code-specific functionality like context menus, keyboard navigation, theming, accessibility, and dependency injection integration. These widgets serve as the primary tree components used throughout the VS Code workbench for file explorers, debug views, search results, and other hierarchical data presentations.
Expand Down Expand Up @@ -153,5 +149,3 @@ const options = {
- Implement **efficient data sources** that avoid unnecessary data fetching
- Consider **virtualization settings** for large datasets
- Use **identity providers** for efficient updates and state preservation

---
17 changes: 10 additions & 7 deletions .github/prompts/component.prompt.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
mode: agent
description: 'Help author a component specification for an agent.'
description: 'Help author a component specification instructions file for an agent.'
tools: ['edit', 'search', 'usages', 'vscodeAPI', 'fetch', 'extensions', 'todos']
---

Expand All @@ -9,11 +9,11 @@ Your goal is to create a component overview in markdown given the context provid
</overview>

<format>
# [Component Name] Overview
---
description: 'A short description of when to use the instructions in this file.'
---

**Location**: `src/vs/[path/to/component]`
**Type**: [Service/Contribution/Extension/API/etc.]
**Layer (if applicable)**: [base/platform/editor/workbench/code/server]
# [Component Name] Overview

## Purpose

Expand Down Expand Up @@ -44,15 +44,18 @@ List all the key files and a brief description of their purpose:

- Reserve a section for any specific development practices or patterns relevant to this component. These will be edited by a developer or agent as needed.

---
## Learnings

- Reserve a section for learnings that will be added by the agent. This section should be empty initially and only updated when the agent learns something based on separate instructions.
</format>

<instructions>
- **Create** a new overview file if one is not specified: `.components/[component-name].md`
- **Create** a new overview file if one is not specified: `.github/[component-name].instructions.md`
- **Fill** each section with component-specific details
- **Gather** information from the attached context and use available tools if needed to complete your understanding
- **Ask** the user for clarification if you cannot fill out a section with accurate information
- **Use complete file paths** from repository root (e.g., `src/vs/workbench/services/example/browser/exampleService.ts`)
- **Keep** descriptions concise but comprehensive
- **Use file references** instead of code snippets when making references to code as otherwise the code may become outdated
- **Reserve an empty section** for Learnings to be filled in later by the agent
</instructions>
Loading