Add user-profile-sample with three variations

Co-authored-by: pierceboggan <1091304+pierceboggan@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-10-27 05:05:48 +00:00
parent fbf33025da
commit c6d0bd064e
10 changed files with 2233 additions and 0 deletions

4
user-profile-sample/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
out
node_modules
.vscode-test
*.vsix

17
user-profile-sample/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

18
user-profile-sample/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@ -0,0 +1,8 @@
.vscode/**
.vscode-test/**
src/**
.gitignore
.eslintrc.json
eslint.config.mjs
**/*.map
**/*.ts

View File

@ -0,0 +1,100 @@
# User Profile Sample - Three Variations
This sample demonstrates **three different variations** of implementing user profile management in a VS Code extension. Each variation shows a different approach to storing and retrieving user data.
## The Three Variations
### Variation 1: In-Memory Storage
**Simplest approach** - Data exists only during the extension's lifetime.
**Characteristics:**
- ✅ Fast and simple
- ❌ Data is lost when VS Code restarts
- ❌ Not suitable for persistent data
**Use case:** Temporary session data, cache
**Commands:**
- `User Profile: Set Profile (Variation 1 - In-Memory)` - Set user profile
- `User Profile: Show Profile (Variation 1 - In-Memory)` - Display current profile
### Variation 2: Workspace State Storage
**Workspace-specific persistence** - Data persists per workspace.
**Characteristics:**
- ✅ Survives VS Code restarts
- ✅ Different workspaces can have different profiles
- ❌ Data is not shared across workspaces
**Use case:** Project-specific user preferences, workspace-specific settings
**Commands:**
- `User Profile: Set Profile (Variation 2 - Workspace State)` - Set workspace profile
- `User Profile: Show Profile (Variation 2 - Workspace State)` - Display workspace profile
### Variation 3: Global State with Settings Integration
**Global persistence with defaults** - Data persists globally across all workspaces.
**Characteristics:**
- ✅ Survives VS Code restarts
- ✅ Shared across all workspaces
- ✅ Integrates with VS Code settings for default values
- ✅ Most feature-rich
**Use case:** User identity, global preferences, account information
**Commands:**
- `User Profile: Set Profile (Variation 3 - Global State)` - Set global profile
- `User Profile: Show Profile (Variation 3 - Global State)` - Display global profile
**Settings:**
- `userProfile.defaultName` - Default user name
- `userProfile.defaultEmail` - Default user email
## How to Run
1. Run `npm install` in terminal to install dependencies
2. Run the `Run Extension` target in the Debug View (or press `F5`)
3. In the new VS Code window, open the Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`)
4. Try any of the six commands to see each variation in action
## Comparison Table
| Feature | Variation 1 | Variation 2 | Variation 3 |
|---------|-------------|-------------|-------------|
| **Storage Type** | In-Memory | Workspace State | Global State |
| **Persists on Restart** | ❌ No | ✅ Yes | ✅ Yes |
| **Shared Across Workspaces** | N/A | ❌ No | ✅ Yes |
| **Settings Integration** | ❌ No | ❌ No | ✅ Yes |
| **Complexity** | Low | Medium | High |
| **Best For** | Session data | Workspace preferences | User identity |
## VS Code API Used
### `vscode` module
- [`ExtensionContext.workspaceState`](https://code.visualstudio.com/api/references/vscode-api#ExtensionContext.workspaceState) - Workspace-specific storage
- [`ExtensionContext.globalState`](https://code.visualstudio.com/api/references/vscode-api#ExtensionContext.globalState) - Global storage
- [`Memento`](https://code.visualstudio.com/api/references/vscode-api#Memento) - Key-value storage interface
- [`workspace.getConfiguration`](https://code.visualstudio.com/api/references/vscode-api#workspace.getConfiguration) - Access extension settings
- [`window.showInputBox`](https://code.visualstudio.com/api/references/vscode-api#window.showInputBox) - User input
- [`window.showInformationMessage`](https://code.visualstudio.com/api/references/vscode-api#window.showInformationMessage) - Display messages
### Contribution Points
- [`contributes.commands`](https://code.visualstudio.com/api/references/contribution-points#contributes.commands) - Register commands
- [`contributes.configuration`](https://code.visualstudio.com/api/references/contribution-points#contributes.configuration) - Define settings
## Key Learning Points
1. **In-Memory vs Persistent Storage**: Understand when to use temporary vs persistent data storage
2. **Workspace vs Global State**: Learn the difference between workspace-specific and global data
3. **Settings Integration**: See how to provide default values through VS Code settings
4. **Memento API**: Master the key-value storage interface for VS Code extensions
## Implementation Details
Each variation is implemented as a separate class:
- `InMemoryProfileManager` - Simple in-memory storage
- `WorkspaceProfileManager` - Uses `workspaceState` Memento
- `GlobalProfileManager` - Uses `globalState` Memento with settings fallback
All three variations implement the same interface for setting and getting user profiles, making it easy to compare their different storage mechanisms.

View File

@ -0,0 +1,44 @@
/**
* ESLint configuration for the project.
*
* See https://eslint.style and https://typescript-eslint.io for additional linting options.
*/
// @ts-check
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import stylistic from '@stylistic/eslint-plugin';
export default tseslint.config(
{
ignores: [
'.vscode-test',
'out',
]
},
js.configs.recommended,
...tseslint.configs.recommended,
...tseslint.configs.stylistic,
{
plugins: {
'@stylistic': stylistic
},
rules: {
'curly': 'warn',
'@stylistic/semi': ['warn', 'always'],
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/naming-convention': [
'warn',
{
'selector': 'import',
'format': ['camelCase', 'PascalCase']
}
],
'@typescript-eslint/no-unused-vars': [
'error',
{
'argsIgnorePattern': '^_'
}
]
}
}
);

1737
user-profile-sample/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
{
"name": "user-profile-sample",
"displayName": "User Profile Sample",
"description": "Sample showing three variations of user profile management",
"version": "0.0.1",
"publisher": "vscode-samples",
"repository": "https://github.com/Microsoft/vscode-extension-samples/user-profile-sample",
"engines": {
"vscode": "^1.100.0"
},
"categories": [
"Other"
],
"activationEvents": [],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "userProfile.variation1.set",
"title": "User Profile: Set Profile (Variation 1 - In-Memory)"
},
{
"command": "userProfile.variation1.show",
"title": "User Profile: Show Profile (Variation 1 - In-Memory)"
},
{
"command": "userProfile.variation2.set",
"title": "User Profile: Set Profile (Variation 2 - Workspace State)"
},
{
"command": "userProfile.variation2.show",
"title": "User Profile: Show Profile (Variation 2 - Workspace State)"
},
{
"command": "userProfile.variation3.set",
"title": "User Profile: Set Profile (Variation 3 - Global State)"
},
{
"command": "userProfile.variation3.show",
"title": "User Profile: Show Profile (Variation 3 - Global State)"
}
],
"configuration": {
"title": "User Profile",
"properties": {
"userProfile.defaultName": {
"type": "string",
"default": "Guest",
"description": "Default user name for Variation 3"
},
"userProfile.defaultEmail": {
"type": "string",
"default": "guest@example.com",
"description": "Default user email for Variation 3"
}
}
}
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"lint": "eslint",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@stylistic/eslint-plugin": "^2.9.0",
"@types/node": "^22",
"@types/vscode": "^1.100.0",
"eslint": "^9.13.0",
"typescript": "^5.8.2",
"typescript-eslint": "^8.26.0"
}
}

View File

@ -0,0 +1,218 @@
import * as vscode from 'vscode';
// Interface for user profile
interface UserProfile {
name: string;
email: string;
role?: string;
}
/**
* VARIATION 1: In-Memory Storage
* Simplest approach - data exists only during the extension's lifetime
* Data is lost when VS Code is restarted
*/
class InMemoryProfileManager {
private profile: UserProfile | null = null;
setProfile(profile: UserProfile): void {
this.profile = profile;
}
getProfile(): UserProfile | null {
return this.profile;
}
}
/**
* VARIATION 2: Workspace State Storage
* Data persists per workspace
* Different workspaces can have different profiles
*/
class WorkspaceProfileManager {
private static readonly PROFILE_KEY = 'userProfile';
constructor(private workspaceState: vscode.Memento) {}
async setProfile(profile: UserProfile): Promise<void> {
await this.workspaceState.update(WorkspaceProfileManager.PROFILE_KEY, profile);
}
getProfile(): UserProfile | null {
return this.workspaceState.get<UserProfile>(WorkspaceProfileManager.PROFILE_KEY) || null;
}
}
/**
* VARIATION 3: Global State Storage with Settings Integration
* Data persists globally across all workspaces
* Integrates with VS Code settings for default values
*/
class GlobalProfileManager {
private static readonly PROFILE_KEY = 'userProfile';
constructor(private globalState: vscode.Memento) {}
async setProfile(profile: UserProfile): Promise<void> {
await this.globalState.update(GlobalProfileManager.PROFILE_KEY, profile);
}
getProfile(): UserProfile | null {
const profile = this.globalState.get<UserProfile>(GlobalProfileManager.PROFILE_KEY);
if (profile) {
return profile;
}
// Fallback to default values from settings
const config = vscode.workspace.getConfiguration('userProfile');
const defaultName = config.get<string>('defaultName', 'Guest');
const defaultEmail = config.get<string>('defaultEmail', 'guest@example.com');
return {
name: defaultName,
email: defaultEmail,
role: 'Default User'
};
}
}
export function activate(context: vscode.ExtensionContext) {
console.log('User Profile Sample extension is now active!');
// Initialize all three variations
const inMemoryManager = new InMemoryProfileManager();
const workspaceManager = new WorkspaceProfileManager(context.workspaceState);
const globalManager = new GlobalProfileManager(context.globalState);
// VARIATION 1 Commands: In-Memory
context.subscriptions.push(
vscode.commands.registerCommand('userProfile.variation1.set', async () => {
const name = await vscode.window.showInputBox({
prompt: 'Enter your name',
placeHolder: 'John Doe'
});
if (!name) {
return;
}
const email = await vscode.window.showInputBox({
prompt: 'Enter your email',
placeHolder: 'john.doe@example.com'
});
if (!email) {
return;
}
inMemoryManager.setProfile({ name, email });
vscode.window.showInformationMessage(
`Profile saved (In-Memory). Note: This will be lost when VS Code restarts.`
);
})
);
context.subscriptions.push(
vscode.commands.registerCommand('userProfile.variation1.show', () => {
const profile = inMemoryManager.getProfile();
if (profile) {
vscode.window.showInformationMessage(
`In-Memory Profile: ${profile.name} (${profile.email})`
);
} else {
vscode.window.showWarningMessage('No profile set for Variation 1');
}
})
);
// VARIATION 2 Commands: Workspace State
context.subscriptions.push(
vscode.commands.registerCommand('userProfile.variation2.set', async () => {
const name = await vscode.window.showInputBox({
prompt: 'Enter your name',
placeHolder: 'John Doe'
});
if (!name) {
return;
}
const email = await vscode.window.showInputBox({
prompt: 'Enter your email',
placeHolder: 'john.doe@example.com'
});
if (!email) {
return;
}
await workspaceManager.setProfile({ name, email });
vscode.window.showInformationMessage(
`Profile saved (Workspace State). This persists per workspace.`
);
})
);
context.subscriptions.push(
vscode.commands.registerCommand('userProfile.variation2.show', () => {
const profile = workspaceManager.getProfile();
if (profile) {
vscode.window.showInformationMessage(
`Workspace Profile: ${profile.name} (${profile.email})`
);
} else {
vscode.window.showWarningMessage('No profile set for Variation 2');
}
})
);
// VARIATION 3 Commands: Global State with Settings
context.subscriptions.push(
vscode.commands.registerCommand('userProfile.variation3.set', async () => {
const name = await vscode.window.showInputBox({
prompt: 'Enter your name',
placeHolder: 'John Doe'
});
if (!name) {
return;
}
const email = await vscode.window.showInputBox({
prompt: 'Enter your email',
placeHolder: 'john.doe@example.com'
});
if (!email) {
return;
}
const role = await vscode.window.showInputBox({
prompt: 'Enter your role (optional)',
placeHolder: 'Developer'
});
await globalManager.setProfile({ name, email, role: role || 'User' });
vscode.window.showInformationMessage(
`Profile saved (Global State). This persists across all workspaces.`
);
})
);
context.subscriptions.push(
vscode.commands.registerCommand('userProfile.variation3.show', () => {
const profile = globalManager.getProfile();
if (profile) {
const roleText = profile.role ? ` - ${profile.role}` : '';
vscode.window.showInformationMessage(
`Global Profile: ${profile.name} (${profile.email})${roleText}`
);
} else {
vscode.window.showWarningMessage('No profile set for Variation 3');
}
})
);
}
export function deactivate() {}

View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"lib": ["ES2022"],
"sourceMap": true,
"rootDir": "src",
"outDir": "out",
"strict": true,
"noUnusedLocals": true
},
"exclude": ["node_modules", ".vscode-test"]
}