full PC config setup

shifting towards manual symlinks for more complex setup than laptop, allows for GUI settings changes to actually apply, and is much easier than nix-ifying every config
This commit is contained in:
greyweather committed 2026-07-12 04:01:28 +01:00
1 parent 19e8f0a6d5
commit 0f018cd2e3
149 files changed
+9539 -478

No files matched your search

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CHOICE_WORKSPACE_DESC = exports.CHOICE_WORKSPACE_LABEL = exports.CHOICE_GLOBAL_DESC = exports.CHOICE_GLOBAL_LABEL = exports.PROMPT_CONFIRM_OVERWRITE = exports.PROMPT_CONFIRM_DELETE = exports.PROMPT_SELECT_PATTERN = exports.PROMPT_SELECT_SCOPE = exports.PROMPT_PATTERN_NAME_PLACEHOLDER = exports.PROMPT_PATTERN_NAME = exports.INFO_PATTERN_DELETED = exports.INFO_PATTERN_SAVED = exports.INFO_PATTERN_LOADED = exports.INFO_NO_PATTERNS = exports.ERR_MANAGING_PATTERNS = exports.ERR_LOADING_PATTERN = exports.ERR_SAVING_PATTERN = exports.ERR_PATTERN_NAME_EMPTY = exports.ERR_NO_SEARCH_STATE = exports.UI_MANAGE_TITLE = exports.UI_SECTION_USER = exports.UI_SECTION_WORKSPACE = exports.UI_NO_PATTERNS_FOUND = exports.UI_NO_PATTERNS = exports.MSG_TYPE_SAVE = exports.MSG_TYPE_LOAD = exports.MSG_TYPE_DELETE = exports.MSG_TYPE_PATTERNS = exports.MSG_TYPE_READY = exports.COMMAND_MANAGE = exports.SCOPE_WORKSPACE = exports.SCOPE_GLOBAL = exports.CONFIG_KEY_WORKSPACE_PATTERNS = exports.CONFIG_KEY_USER_PATTERNS = exports.CONFIG_NAMESPACE = void 0;
exports.CONFIG_NAMESPACE = 'patternStore';
exports.CONFIG_KEY_USER_PATTERNS = 'savedPatterns';
exports.CONFIG_KEY_WORKSPACE_PATTERNS = 'workspacePatterns';
exports.SCOPE_GLOBAL = 'global';
exports.SCOPE_WORKSPACE = 'workspace';
exports.COMMAND_MANAGE = 'patternStore.manage';
exports.MSG_TYPE_READY = 'ready';
exports.MSG_TYPE_PATTERNS = 'patterns';
exports.MSG_TYPE_DELETE = 'delete';
exports.MSG_TYPE_LOAD = 'load';
exports.MSG_TYPE_SAVE = 'save';
exports.UI_NO_PATTERNS = 'No patterns yet';
exports.UI_NO_PATTERNS_FOUND = 'No patterns found';
exports.UI_SECTION_WORKSPACE = 'Workspace';
exports.UI_SECTION_USER = 'User';
exports.UI_MANAGE_TITLE = 'Manage Patterns';
exports.ERR_NO_SEARCH_STATE = 'Could not read current search state';
exports.ERR_PATTERN_NAME_EMPTY = 'Pattern name cannot be empty';
exports.ERR_SAVING_PATTERN = 'Error saving pattern';
exports.ERR_LOADING_PATTERN = 'Error loading pattern';
exports.ERR_MANAGING_PATTERNS = 'Error managing patterns';
exports.INFO_NO_PATTERNS = 'No saved patterns found. Use "PatternStore: Save Pattern" to create one.';
exports.INFO_PATTERN_LOADED = 'Loaded pattern';
exports.INFO_PATTERN_SAVED = 'Pattern saved';
exports.INFO_PATTERN_DELETED = 'Pattern deleted';
exports.PROMPT_PATTERN_NAME = 'Enter a name for this pattern';
exports.PROMPT_PATTERN_NAME_PLACEHOLDER = 'e.g., "Replace quotes with angles"';
exports.PROMPT_SELECT_SCOPE = 'Choose storage scope';
exports.PROMPT_SELECT_PATTERN = 'Select a pattern to load';
exports.PROMPT_CONFIRM_DELETE = 'Delete pattern';
exports.PROMPT_CONFIRM_OVERWRITE = 'already exists. Overwrite?';
exports.CHOICE_GLOBAL_LABEL = 'Global';
exports.CHOICE_GLOBAL_DESC = 'Available in all workspaces';
exports.CHOICE_WORKSPACE_LABEL = 'Workspace';
exports.CHOICE_WORKSPACE_DESC = 'Only for this workspace';
//# sourceMappingURL=constants.js.map
@@ -0,0 +1,127 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const storage = __importStar(require("./storage"));
const searchCtx = __importStar(require("./searchCtx"));
const WebviewManager_1 = require("./webview/WebviewManager");
/**
* Called when the extension is activated
*/
function activate(context) {
console.log('PatternStore extension is now active!');
// Register command: Manage Patterns
const manageCommand = vscode.commands.registerCommand('patternStore.manage', async () => {
await managePatternsCommand(context.extensionUri);
});
context.subscriptions.push(manageCommand);
}
/**
* Called when the extension is deactivated
*/
function deactivate() {
console.log('PatternStore extension is now deactivated');
}
/**
* Command: Save the current search state as a pattern
*/
async function savePatternCommand() {
try {
vscode.window.showInformationMessage('PatternStore: Save Pattern command executed!');
// Get current search state
const searchState = await searchCtx.getCurrentSearchState();
if (!searchState) {
vscode.window.showErrorMessage('Could not read current search state');
return;
}
// Prompt for pattern name
const label = await vscode.window.showInputBox({
prompt: 'Enter a name for this pattern',
placeHolder: 'e.g., "Replace quotes with angles"',
validateInput: (value) => {
if (!value || value.trim().length === 0) {
return 'Pattern name cannot be empty';
}
return null;
}
});
if (!label) {
return; // User cancelled
}
// Ask for scope
const scopeChoice = await vscode.window.showQuickPick([
{ label: 'Global', description: 'Available in all workspaces', value: 'global' },
{ label: 'Workspace', description: 'Only for this workspace', value: 'workspace' }
], { placeHolder: 'Choose storage scope' });
if (!scopeChoice) {
return; // User cancelled
}
// Create pattern object
const pattern = {
id: 'new', // Temporary ID for new patterns
label: label.trim(),
find: searchState.find || '',
replace: searchState.replace || '',
flags: searchState.flags || {
isRegex: false,
isCaseSensitive: false,
matchWholeWord: false,
isMultiline: false
},
scope: scopeChoice.value
};
// Check if pattern exists (will check when we implement storage)
const exists = storage.patternExists(pattern.label, pattern.scope);
if (exists) {
const overwrite = await vscode.window.showWarningMessage(`A pattern named "${pattern.label}" already exists. Overwrite?`, 'Yes', 'No');
if (overwrite !== 'Yes') {
return;
}
}
// Save pattern
await storage.savePattern(pattern);
}
catch (error) {
vscode.window.showErrorMessage(`Error saving pattern: ${error}`);
}
}
async function managePatternsCommand(extensionUri) {
console.log('Manage Patterns command pressed - opening webview');
// For now, just open global patterns. We'll add separate commands later
WebviewManager_1.WebviewManager.show(extensionUri, 'global');
}
//# sourceMappingURL=extension.js.map
@@ -0,0 +1,129 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCurrentSearchState = getCurrentSearchState;
exports.loadPatternIntoSearch = loadPatternIntoSearch;
const vscode = __importStar(require("vscode"));
/**
* Get the current search state from the Search panel
* Returns null if unable to get the state
*
* NOTE: VS Code doesn't expose search panel state via API.
* This function tries to use editor selection as fallback.
*/
async function getCurrentSearchState() {
// Try to get selected text from active editor
const editor = vscode.window.activeTextEditor;
const selection = editor?.document.getText(editor.selection);
if (selection && selection.length > 0) {
// Use selection as find text
return {
find: selection,
replace: '',
flags: {
isRegex: false,
isCaseSensitive: false,
matchWholeWord: false,
isMultiline: false
}
};
}
// No selection available - return null
// User will need to enter manually
return null;
}
/**
* Resolve placeholders like ${prompt:varname} in multiple strings
* Prompts once per unique placeholder name and reuses the value
*/
async function resolvePlaceholdersMultiple(texts) {
const RE = /\$\{prompt:([^}]+)\}/g;
// Collect all unique placeholder names across all texts
const allNames = new Set();
for (const text of texts) {
Array.from(text.matchAll(RE), m => m[1]).forEach(name => allNames.add(name));
}
const vals = {};
// Prompt once for each unique placeholder
for (const name of allNames) {
const value = await vscode.window.showInputBox({
prompt: `Value for ${name}`,
placeHolder: name
});
if (value === undefined) {
return undefined; // User cancelled
}
vals[name] = value;
}
// Replace placeholders in all texts using the collected values
return texts.map(text => text.replace(RE, (_, name) => vals[name] ?? ""));
}
/**
* Resolve placeholders like ${prompt:varname} in a string (single text version)
*/
async function resolvePlaceholders(text) {
const result = await resolvePlaceholdersMultiple([text]);
return result ? result[0] : undefined;
}
async function loadPatternIntoSearch(pattern) {
try {
const hasReplace = pattern.replace && pattern.replace.trim().length > 0;
const textsToResolve = hasReplace ? [pattern.find, pattern.replace] : [pattern.find];
const resolved = await resolvePlaceholdersMultiple(textsToResolve);
if (!resolved) {
return; // User cancelled
}
const find = resolved[0];
const replace = hasReplace ? resolved[1] : '';
const commandArgs = {
query: find,
replace: replace,
triggerSearch: false, // Don't auto-trigger search
isRegex: pattern.flags.isRegex,
isCaseSensitive: pattern.flags.isCaseSensitive,
matchWholeWord: pattern.flags.matchWholeWord,
preserveCase: false,
filesToInclude: pattern.filesToInclude || '',
filesToExclude: pattern.filesToExclude || ''
};
await vscode.commands.executeCommand("workbench.action.findInFiles", commandArgs);
vscode.window.showInformationMessage(`✅ Loaded pattern: "${pattern.label}"`);
}
catch (error) {
vscode.window.showErrorMessage(`Failed to load pattern: ${error}`);
throw error;
}
}
//# sourceMappingURL=searchCtx.js.map
@@ -0,0 +1,158 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAllPatterns = getAllPatterns;
exports.savePattern = savePattern;
exports.deletePattern = deletePattern;
exports.renamePattern = renamePattern;
exports.patternExists = patternExists;
const vscode = __importStar(require("vscode"));
const C = __importStar(require("./constants"));
/**
* Get patterns from settings and add runtime IDs
*/
function getPatternsByScope(scope) {
const config = vscode.workspace.getConfiguration(C.CONFIG_NAMESPACE);
const configKey = scope === 'global' ? C.CONFIG_KEY_USER_PATTERNS : C.CONFIG_KEY_WORKSPACE_PATTERNS;
let storedPatterns;
if (scope === 'global') {
storedPatterns = config.inspect(C.CONFIG_KEY_USER_PATTERNS)?.globalValue || [];
}
else {
storedPatterns = config.inspect(C.CONFIG_KEY_WORKSPACE_PATTERNS)?.workspaceValue || [];
}
// Add runtime IDs and ensure scope is set
return storedPatterns.map((p, index) => ({
...p,
id: `${scope}-${index}`, // Index-based runtime ID
scope: scope
}));
}
function getAllPatterns() {
const workspace = getPatternsByScope('workspace');
const global = getPatternsByScope('global');
// Return all patterns - duplicates across scopes are allowed
return [...workspace, ...global];
}
async function savePattern(pattern) {
const config = vscode.workspace.getConfiguration(C.CONFIG_NAMESPACE);
const configKey = pattern.scope === 'global' ? C.CONFIG_KEY_USER_PATTERNS : C.CONFIG_KEY_WORKSPACE_PATTERNS;
const target = pattern.scope === 'global'
? vscode.ConfigurationTarget.Global
: vscode.ConfigurationTarget.Workspace;
// Read fresh patterns with runtime IDs
const patternsWithIds = getPatternsByScope(pattern.scope);
// Find existing pattern by ID (runtime ID tells us the index it came from)
const existingIndex = patternsWithIds.findIndex(p => p.id === pattern.id);
const isUpdate = existingIndex !== -1;
// Strip runtime ID before saving
const { id, ...storedPattern } = pattern;
// Create array of stored patterns (without IDs)
let storedPatterns = patternsWithIds.map(p => {
const { id, ...stored } = p;
return stored;
});
if (isUpdate) {
// Update existing pattern IN PLACE (maintains order)
storedPatterns[existingIndex] = storedPattern;
}
else {
// New pattern - add at beginning
storedPatterns.unshift(storedPattern);
}
// Save to settings (without IDs)
await config.update(configKey, storedPatterns, target);
// Only show message if it's a new pattern (not an update)
if (!isUpdate) {
vscode.window.showInformationMessage(`✅ Pattern "${pattern.label}" saved to ${pattern.scope} settings`);
}
}
async function deletePattern(id, scope) {
const config = vscode.workspace.getConfiguration(C.CONFIG_NAMESPACE);
const configKey = scope === 'global' ? C.CONFIG_KEY_USER_PATTERNS : C.CONFIG_KEY_WORKSPACE_PATTERNS;
const target = scope === 'global'
? vscode.ConfigurationTarget.Global
: vscode.ConfigurationTarget.Workspace;
// Read fresh patterns with runtime IDs
const patternsWithIds = getPatternsByScope(scope);
// Find pattern by runtime ID
const patternToDelete = patternsWithIds.find(p => p.id === id);
if (!patternToDelete) {
vscode.window.showWarningMessage(`Pattern not found in ${scope} settings`);
return;
}
// Filter out the pattern and strip IDs
const storedPatterns = patternsWithIds
.filter(p => p.id !== id)
.map(p => {
const { id, ...stored } = p;
return stored;
});
// Save updated list (without IDs)
await config.update(configKey, storedPatterns, target);
vscode.window.showInformationMessage(`🗑️ Pattern "${patternToDelete.label}" deleted from ${scope} settings`);
}
async function renamePattern(id, newLabel, scope) {
const config = vscode.workspace.getConfiguration(C.CONFIG_NAMESPACE);
const configKey = scope === 'global' ? C.CONFIG_KEY_USER_PATTERNS : C.CONFIG_KEY_WORKSPACE_PATTERNS;
const target = scope === 'global'
? vscode.ConfigurationTarget.Global
: vscode.ConfigurationTarget.Workspace;
// Read fresh patterns with runtime IDs
const patternsWithIds = getPatternsByScope(scope);
// Find pattern by runtime ID
const pattern = patternsWithIds.find(p => p.id === id);
if (!pattern) {
vscode.window.showWarningMessage(`Pattern not found in ${scope} settings`);
return;
}
const oldLabel = pattern.label;
// Update label and strip IDs for saving
const storedPatterns = patternsWithIds.map(p => {
const { id: _id, ...stored } = p;
if (p.id === id) {
return { ...stored, label: newLabel };
}
return stored;
});
// Save updated list (without IDs)
await config.update(configKey, storedPatterns, target);
vscode.window.showInformationMessage(`✏️ Pattern renamed from "${oldLabel}" to "${newLabel}" in ${scope} settings`);
}
function patternExists(label, scope) {
const patterns = getPatternsByScope(scope);
return patterns.some(p => p.label === label);
}
//# sourceMappingURL=storage.js.map
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
@@ -0,0 +1,266 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebviewManager = void 0;
const vscode = __importStar(require("vscode"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const storage = __importStar(require("../storage"));
const searchCtx = __importStar(require("../searchCtx"));
/**
* Manages the webview panel for pattern management
*/
class WebviewManager {
/**
* Create or show the webview panel
*/
static show(extensionUri, scope) {
const column = vscode.window.activeTextEditor
? vscode.window.activeTextEditor.viewColumn
: undefined;
// If we already have a panel, show it
if (WebviewManager.currentPanel) {
WebviewManager.currentPanel.panel.reveal(column);
return;
}
const panel = vscode.window.createWebviewPanel('patternStoreManage', 'PatternStore', column || vscode.ViewColumn.One, {
enableScripts: true,
retainContextWhenHidden: true,
});
WebviewManager.currentPanel = new WebviewManager(panel, extensionUri, scope);
}
constructor(panel, extensionUri, scope) {
this.disposables = [];
this.isInternalSave = false;
this.panel = panel;
this.extensionUri = extensionUri;
this.scope = scope;
// Set initial HTML content
this.panel.webview.html = this.getHtmlContent();
// Listen for when the panel is disposed
this.panel.onDidDispose(() => this.dispose(), null, this.disposables);
// Handle messages from the webview
this.panel.webview.onDidReceiveMessage(message => {
this.handleMessage(message);
}, null, this.disposables);
// Watch for external config changes
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('patternStore')) {
this.handleExternalConfigChange();
}
}, null, this.disposables);
this.sendPatterns();
}
sendPatterns(selectId, selectScope, clearSelection) {
const allPatterns = storage.getAllPatterns();
const workspacePatterns = allPatterns.filter(p => p.scope === 'workspace');
const userPatterns = allPatterns.filter(p => p.scope === 'global');
const message = {
type: 'patterns',
workspace: workspacePatterns,
user: userPatterns
};
if (selectId && selectScope) {
message.selectPattern = {
id: selectId,
scope: selectScope
};
}
if (clearSelection) {
message.clearSelection = true;
}
this.panel.webview.postMessage(message);
}
/**
* Handle external configuration changes (e.g., manual edits to settings.json)
*/
handleExternalConfigChange() {
// Don't show notification if this was an internal save
if (this.isInternalSave) {
this.isInternalSave = false;
return;
}
// Show warning to user for actual external changes
vscode.window.showWarningMessage('Pattern settings changed externally. Webview reloaded.');
// Force full reload - this clears any dirty state and rebuilds runtime IDs
// Pass clearSelection flag to force the webview to clear the details view
this.sendPatterns(undefined, undefined, true);
}
async handleMessage(message) {
console.log('Received message from webview:', message);
switch (message.type) {
case 'ready':
// Webview is ready, send patterns
this.sendPatterns();
break;
case 'delete':
await this.handleDelete(message.id, message.scope);
break;
case 'load':
await this.handleLoad(message.id, message.scope, message.pattern);
break;
case 'create':
await this.handleCreate(message.scope);
break;
case 'save':
await this.handleSave(message.pattern);
break;
}
}
async handleCreate(scope) {
// Generate unique label for new pattern
const existingPatterns = storage.getAllPatterns().filter(p => p.scope === scope);
const baseName = 'New Pattern';
let label = baseName;
let counter = 1;
while (existingPatterns.some(p => p.label === label)) {
counter++;
label = `${baseName} ${counter}`;
}
const newPattern = {
id: 'new', // Temporary ID for new patterns
label: label,
find: '',
replace: '',
flags: {
isRegex: false,
isCaseSensitive: false,
matchWholeWord: false,
isMultiline: false
},
scope: scope
};
// Mark as internal save to suppress external change notification
this.isInternalSave = true;
await storage.savePattern(newPattern);
// New pattern will be at index 0 (savePattern uses unshift)
this.sendPatterns(`${scope}-0`, scope);
}
async handleSave(patternData) {
const { id, label, find, replace, flags, filesToInclude, filesToExclude, scope } = patternData;
const pattern = {
id: id, // Preserve existing ID
label: label,
find: find,
replace: replace,
flags: flags,
filesToInclude: filesToInclude,
filesToExclude: filesToExclude,
scope: scope
};
// Mark as internal save to suppress external change notification
this.isInternalSave = true;
await storage.savePattern(pattern);
this.sendPatterns(id, scope);
}
async handleDelete(id, scope) {
// Find pattern to get label for confirmation
const allPatterns = storage.getAllPatterns();
const pattern = allPatterns.find(p => p.id === id && p.scope === scope);
if (!pattern) {
vscode.window.showErrorMessage(`Pattern not found`);
return;
}
// Confirm deletion
const confirm = await vscode.window.showWarningMessage(`Delete pattern "${pattern.label}"?`, { modal: true }, 'Delete');
if (confirm === 'Delete') {
// Mark as internal save to suppress external change notification
this.isInternalSave = true;
await storage.deletePattern(id, scope);
// Refresh pattern list
this.sendPatterns();
}
}
async handleLoad(id, scope, providedPattern) {
let pattern = providedPattern;
// If no pattern was provided, look it up
if (!pattern) {
const allPatterns = storage.getAllPatterns();
pattern = allPatterns.find(p => p.id === id && p.scope === scope);
if (!pattern) {
vscode.window.showErrorMessage(`Pattern "${id}" not found`);
return;
}
}
await searchCtx.loadPatternIntoSearch(pattern);
}
getHtmlContent() {
// Generate nonce for CSP
const nonce = this.getNonce();
// Get URIs for webview resources
const cspSource = this.panel.webview.cspSource;
// Load HTML, CSS, and JS from files
const htmlPath = path.join(this.extensionUri.fsPath, 'src', 'webview', 'html', 'patternManager.html');
const cssPath = path.join(this.extensionUri.fsPath, 'src', 'webview', 'css', 'patternManager.css');
const jsPath = path.join(this.extensionUri.fsPath, 'src', 'webview', 'js', 'patternManager.js');
let html = fs.readFileSync(htmlPath, 'utf8');
const css = fs.readFileSync(cssPath, 'utf8');
const js = fs.readFileSync(jsPath, 'utf8');
// Build style tag with nonce
const styleTag = `<style nonce="${nonce}">\n${css}\n </style>`;
// Replace placeholders
html = html.replace(/{{nonce}}/g, nonce);
html = html.replace(/{{cspSource}}/g, cspSource);
html = html.replace(/{{styleTag}}/g, styleTag);
html = html.replace(/{{script}}/g, js);
return html;
}
/**
* Generate a nonce for CSP
*/
getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
/**
* Clean up resources
*/
dispose() {
WebviewManager.currentPanel = undefined;
this.panel.dispose();
while (this.disposables.length) {
const disposable = this.disposables.pop();
if (disposable) {
disposable.dispose();
}
}
}
}
exports.WebviewManager = WebviewManager;
//# sourceMappingURL=WebviewManager.js.map