Skip to content

Commit 9f4d216

Browse files
committed
refactor(extension): Improve debug logging and context detection logic
1 parent 8ea107b commit 9f4d216

File tree

2 files changed

+106
-59
lines changed

2 files changed

+106
-59
lines changed

snippets/iam-actions.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39955,10 +39955,6 @@
3995539955
"name": "ec2:InstanceAutoRecovery",
3995639956
"reference_href": "https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html#amazonec2-ec2_InstanceAutoRecovery"
3995739957
},
39958-
{
39959-
"name": "ec2:InstanceBandwidthWeighting",
39960-
"reference_href": "https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html#amazonec2-ec2_InstanceBandwidthWeighting"
39961-
},
3996239958
{
3996339959
"name": "ec2:InstanceID",
3996439960
"reference_href": "https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html#amazonec2-ec2_InstanceID"
@@ -298021,4 +298017,4 @@
298021298017
"serviceName": "Tag Editor",
298022298018
"service_prefix": "resource-explorer"
298023298019
}
298024-
}
298020+
}

src/extension.ts

Lines changed: 105 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import * as fs from 'node:fs/promises';
22
import * as path from 'node:path';
33
import * as vscode from 'vscode';
4-
import { CompletionItem, CompletionItemKind, type Disposable, Hover, MarkdownString } from 'vscode';
4+
import { type Disposable, Hover, MarkdownString } from 'vscode';
55

6-
let outputChannel: vscode.OutputChannel;
6+
const DEBUG_ENABLED = false;
7+
export const outputChannel = vscode.window.createOutputChannel('IAM Action Snippets');
8+
9+
export function log(message: string) {
10+
if (DEBUG_ENABLED) {
11+
outputChannel.appendLine(`[DEBUG] ${message}`);
12+
}
13+
}
714

815
interface IamActionData {
916
access_level: string;
@@ -55,11 +62,9 @@ class IamActionMappings {
5562
}
5663
}
5764

58-
outputChannel.appendLine(
59-
`Loaded ${this.iamActionsMap.size} IAM actions across ${this.servicePrefixMap.size} services`,
60-
);
65+
log(`Loaded ${this.iamActionsMap.size} IAM actions across ${this.servicePrefixMap.size} services`);
6166
} catch (error) {
62-
outputChannel.appendLine(`Error loading IAM actions: ${error}`);
67+
log(`Error loading IAM actions: ${error}`);
6368
}
6469
}
6570

@@ -100,8 +105,11 @@ class IamActionMappings {
100105
}
101106

102107
export function activate(context: vscode.ExtensionContext) {
103-
outputChannel = vscode.window.createOutputChannel('IAM Action Snippets');
104-
outputChannel.appendLine('IAM Action Snippets extension activated');
108+
if (DEBUG_ENABLED) {
109+
log('IAM Action Snippets extension activated (debug mode)');
110+
} else {
111+
outputChannel.appendLine('IAM Action Snippets extension activated');
112+
}
105113

106114
const iamActionMappings = new IamActionMappings();
107115
const disposable: Disposable[] = [];
@@ -113,7 +121,7 @@ export function activate(context: vscode.ExtensionContext) {
113121
{
114122
async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
115123
if (await isBelowActionKey(document, position)) {
116-
outputChannel.appendLine(`Providing completion items at position: ${position.line}:${position.character}`);
124+
log(`Providing completion items at position: ${position.line}:${position.character}`);
117125
const allActions = await iamActionMappings.getAllIamActions();
118126
return Promise.all(
119127
allActions.map(async (action) => {
@@ -251,7 +259,7 @@ export function activate(context: vscode.ExtensionContext) {
251259

252260
if (range) {
253261
const word = document.getText(range).replace(/^["']|["']$/g, '');
254-
outputChannel.appendLine(`Providing hover for: ${word}`);
262+
log(`Providing hover for: ${word}`);
255263

256264
if (word.includes('*')) {
257265
const matchingActions = await iamActionMappings.getMatchingActions(word);
@@ -323,77 +331,120 @@ export function activate(context: vscode.ExtensionContext) {
323331
}
324332

325333
export function deactivate() {
326-
outputChannel.appendLine('IAM Action Snippets extension deactivated');
334+
log('IAM Action Snippets extension deactivated');
327335
}
328336

329337
async function isBelowActionKey(document: vscode.TextDocument, position: vscode.Position): Promise<boolean> {
330-
const maxLinesUp = 40;
331-
const startLine = Math.max(0, position.line - maxLinesUp);
332-
const text = document.getText(new vscode.Range(startLine, 0, position.line, position.character));
338+
// Use the full text from the top of the document until the current position
339+
const text = document.getText(new vscode.Range(new vscode.Position(0, 0), position));
333340

341+
// JSON and Terraform
334342
if (document.languageId === 'json' || document.languageId === 'terraform') {
335343
const lines = text.split('\n').reverse();
344+
const jsonRegex = /"action"\s*:\s*\[/i;
345+
const terraformRegex = /action\s*=\s*\[/i;
336346
for (const line of lines) {
337-
const trimmedLine = line.trim().toLowerCase();
338-
if (document.languageId === 'json') {
339-
if (trimmedLine.includes('"action"') && trimmedLine.includes('[')) {
340-
return true;
341-
}
342-
} else if (document.languageId === 'terraform') {
343-
if (trimmedLine.includes('action') && trimmedLine.includes('=') && trimmedLine.includes('[')) {
344-
return true;
345-
}
347+
const trimmedLine = line.trim();
348+
if (document.languageId === 'json' && jsonRegex.test(trimmedLine)) {
349+
return true;
350+
}
351+
if (document.languageId === 'terraform' && terraformRegex.test(trimmedLine)) {
352+
return true;
346353
}
347354
if (trimmedLine.startsWith('}') || trimmedLine.startsWith(']')) {
348355
break;
349356
}
350357
}
351358
}
352359

360+
// YAML / YML
353361
if (document.languageId === 'yaml' || document.languageId === 'yml') {
354-
const lines = text.split('\n').reverse();
355-
for (const line of lines) {
356-
const trimmedLine = line.trim().toLowerCase();
357-
if (
358-
trimmedLine.startsWith('action:') ||
359-
trimmedLine.startsWith('- action:') ||
360-
trimmedLine.startsWith('notaction:') ||
361-
trimmedLine.startsWith('- notaction:')
362-
) {
363-
return true;
362+
const allLines = document.getText().split('\n');
363+
const currentLineIndex = position.line;
364+
const currentLine = allLines[currentLineIndex] || '';
365+
const currentIndent = currentLine.search(/\S/);
366+
log(`[YAML] Current line (${currentLineIndex}): ${currentLine}`);
367+
log(`[YAML] Current indent: ${currentIndent}`);
368+
369+
// If the current line itself is a key, disable autocomplete.
370+
if (/^[-\s]*\w+\s*:/.test(currentLine)) {
371+
log('[YAML] Current line appears to be a key, disabling autocomplete');
372+
return false;
373+
}
374+
375+
// Scan upward for the nearest parent key with lower indent
376+
for (let i = currentLineIndex - 1; i >= 0; i--) {
377+
const line = allLines[i];
378+
const trimmedLine = line.trim();
379+
if (trimmedLine === '' || trimmedLine.startsWith('#')) {
380+
continue;
364381
}
365-
if (
366-
trimmedLine !== '' &&
367-
!trimmedLine.startsWith('-') &&
368-
!trimmedLine.startsWith('- ') &&
369-
!trimmedLine.startsWith('#')
370-
) {
371-
break;
382+
if (!line.includes(':')) {
383+
continue;
384+
}
385+
log(`[YAML] Scanning line ${i}: ${line}`);
386+
const match = line.match(/^([ \t]*)(?:-\s*)?(\w+)\s*:/);
387+
if (match) {
388+
const parentIndent = match[1].length;
389+
if (parentIndent < currentIndent) {
390+
const parentKey = match[2].toLowerCase();
391+
log(`[YAML] Found parent key: ${parentKey} at indent: ${parentIndent}`);
392+
if (parentKey === 'action') {
393+
log(`[YAML] Position is under 'action' key, enabling autocomplete`);
394+
return true;
395+
}
396+
log(`[YAML] Parent key is not 'action', stopping search.`);
397+
break;
398+
}
372399
}
373400
}
374401
}
375402

403+
// CDK TypeScript
376404
if (document.languageId === 'typescript') {
377-
const lines = text.split('\n').reverse();
378-
for (const line of lines) {
379-
const trimmedLine = line.trim().toLowerCase();
380-
if (trimmedLine.includes('actions:') && trimmedLine.includes('[')) {
381-
return true;
382-
}
383-
if (trimmedLine.startsWith('}') || trimmedLine.startsWith(']')) {
405+
const allLines = document.getText().split('\n');
406+
const currentLineIndex = position.line;
407+
const currentLine = allLines[currentLineIndex] || '';
408+
const currentIndent = currentLine.search(/\S/);
409+
log(`[TS] Current line (${currentLineIndex}): ${currentLine}`);
410+
log(`[TS] Current indent: ${currentIndent}`);
411+
412+
const actionsRegex = /actions\s*:\s*\[/;
413+
for (let i = currentLineIndex; i >= 0; i--) {
414+
const line = allLines[i];
415+
log(`[TS] Scanning line ${i}: ${line}`);
416+
if (actionsRegex.test(line)) {
417+
const match = line.match(/^(\s*)/);
418+
const parentIndent = match ? match[1].length : 0;
419+
if (currentIndent > parentIndent) {
420+
log(`[TS] Found actions array starting at line ${i}, enabling autocomplete`);
421+
return true;
422+
}
384423
break;
385424
}
386425
}
387426
}
388427

428+
// CDK Python
389429
if (document.languageId === 'python') {
390-
const lines = text.split('\n').reverse();
391-
for (const line of lines) {
392-
const trimmedLine = line.trim().toLowerCase();
393-
if (trimmedLine.startsWith('actions=') && trimmedLine.includes('[')) {
394-
return true;
395-
}
396-
if (trimmedLine.endsWith(']') || trimmedLine.endsWith('],')) {
430+
const allLines = document.getText().split('\n');
431+
const currentLineIndex = position.line;
432+
const currentLine = allLines[currentLineIndex] || '';
433+
const currentIndent = currentLine.search(/\S/);
434+
log(`[Python] Current line (${currentLineIndex}): ${currentLine}`);
435+
log(`[Python] Current indent: ${currentIndent}`);
436+
437+
const actionsRegex = /actions\s*=\s*\[/;
438+
for (let i = currentLineIndex; i >= 0; i--) {
439+
const line = allLines[i];
440+
log(`[Python] Scanning line ${i}: ${line}`);
441+
if (actionsRegex.test(line)) {
442+
const match = line.match(/^(\s*)/);
443+
const parentIndent = match ? match[1].length : 0;
444+
if (currentIndent > parentIndent) {
445+
log(`[Python] Found actions list starting at line ${i}, enabling autocomplete`);
446+
return true;
447+
}
397448
break;
398449
}
399450
}

0 commit comments

Comments
 (0)