본문 바로가기

[IT/Programming]

VS code (Cursor AI) extension 만들어 보기 (Upward fold additionally (Smart fold/unfold))

반응형
# VS code (Cursor AI) extension 만들어 보기 (Upward fold additionally (Smart fold/unfold)) 들여쓰기 (indent) 고려해서 fold/unfold 해주는 기능이 VS code (Cursor AI) 에 기본적으로 있긴 한데, 젤 아래에서 위쪽으로 fold 해주는 기능이 없고 딱히 extension 을 검색해봐도 안뜨길래 만들어 보기로 결심. 그 내용을 공유합니다. 해당 extension 은 에서 보실 수 있습니다. GitHub repo 는 . ## PH
  • 2025-04-07 : First posting.
## TOC ## 우선 AI 의 도움을 받아서 package.json 을 다음과 같이 설정. fold-unfold-smartly 라는 이름으로 GitHub repository 를 하나 판다. 그리고 VS code marketplace 에 가입을 하고 기타 여러가지 개인 정보들을 넣어준다. 그 정보들을 바탕으로 다음과 같이 package.json 을 만든다. ```[.linenums.scrollable] { "name": "fold-unfold-smartly", "displayName": "Upward fold additionally (Smart fold/unfold)", "description": "Fold and Unfold a specific indentation more smartly. From the downside of the indentation, fold and unfold.", "version": "1.0.0", "publisher": "kipacti", "repository": { "type": "git", "url": "https://github.com/kipid/fold-unfold-smartly" }, "engines": { "vscode": "^1.92.0" }, "categories": [ "Other" ], "activationEvents": [], "main": "./dist/extension.js", "contributes": { "commands": [ { "command": "fold-unfold-smartly.foldUpward", "title": "Smart Fold Upward" } ], "keybindings": [ { "command": "fold-unfold-smartly.foldUpward", "key": "ctrl+alt+f", "when": "editorTextFocus" } ], "menus": { "editor/context": [ { "command": "fold-unfold-smartly.foldUpward", "group": "0_folding" } ] } }, "scripts": { "build": "tsc", "test": "echo \"Error: no test specified\" && exit 1" }, "devDependencies": { "@types/node": "^22.14.0", "@types/vscode": "^1.92.0", "typescript": "^5.8.3", "vscode": "^1.1.37" } } ```/ Cursor AI 가 VS code 버전보다 낮기 때문에 vscode 의 version 을 1.92.0 정도로 적절히 낮춰준다. ```[.linenums] npm i ```/ 명령어로 dependencies 를 깔아준다. ## 기본적으로 TypeScript 로 개발. AI 의 도움 받기. 처음에는 upward fold 기능이 간단할거라 AI 에게 명령만 잘 내리면 순식간에 짜잔하고 extension 이 만들어지길 기대했으나, 아직은 AI 들이 멍청하긴 한가보다. 기본적으로 아주 간단한 케이스에서 동작하도록 까지만 AI 에게 부탁을 해서 짰고, 나머지 세부사항들은 AI 의 도움을 line by line 으로 받으면서 완성해 갔다. 특히나 핵심적인 아래에서부터 위쪽으로 같은 indent 를 찾는 코드 자체를 잘 못 짜줬다. indent 가 작아져도 안되고 같은 레벨이어도 안되고 하는 조건들이 많았는데, 이런건 기본 상식은 아니라 AI 도 이해를 못한듯? 장황하게 설명을 해줘도 코드는 엉망이었다. ## TypeScript compile (tsc) 하고 package 로 VSIX 형태로 만들고 배포 (publish) 까지 하자. ### extension.ts extension.ts 코드는 다음과 같다. 참고만 하시길... ```[.scrollable] import * as vscode from "vscode"; import * as path from "path"; function findCurrentToInitialIndentFoldRange( document: vscode.TextDocument, startLineIndex: number ): { start: number; end: number } | null { try { const startLine = document.lineAt(startLineIndex); if (startLine.isEmptyOrWhitespace) { return null; } const startIndentation = startLine.firstNonWhitespaceCharacterIndex; let endLineIndex = -1; // Find the initial indentation of the same depth let i = startLineIndex - 1; if ( document.lineAt(i).firstNonWhitespaceCharacterIndex <= startIndentation ) { return null; } for (i = startLineIndex - 2; i >= 0; i--) { const currentLine = document.lineAt(i); if (currentLine.isEmptyOrWhitespace) { continue; } const currentIndentation = currentLine.firstNonWhitespaceCharacterIndex; if (currentIndentation === startIndentation) { endLineIndex = i; break; } else if (currentIndentation < startIndentation) { console.log( `[SmartFold] No foldable range found from current to initial indent` ); return null; } } if (endLineIndex !== -1) { console.log( `[SmartFold] Found range from current indent at line ${ startLineIndex + 1 } to initial indent at line ${endLineIndex + 1}` ); return { start: endLineIndex, end: startLineIndex }; } else { console.log( `[SmartFold] No foldable range found from current to initial indent` ); return null; } } catch (error) { console.error( `[SmartFold] findCurrentToInitialIndentFoldRange 오류: ${error}` ); return null; } } export function activate(context: vscode.ExtensionContext) { const iconPath = context.asAbsolutePath(path.join("resources", "icon.svg")); const decorationType = vscode.window.createTextEditorDecorationType({ before: { contentIconPath: iconPath, width: "1em", height: ".7em", margin: "0 -1em 0 0", }, }); function updateDecorations(editor: vscode.TextEditor | undefined) { if (editor) { const decorations: vscode.DecorationOptions[] = []; for (let i = 2; i < editor.document.lineCount; i++) { const range = findCurrentToInitialIndentFoldRange(editor.document, i); if (range) { decorations.push({ range: new vscode.Range(i, 0, i, 0) }); } } editor.setDecorations(decorationType, decorations); } } // 현재 활성화된 에디터에 대해 데코레이션 업데이트 const editor = vscode.window.activeTextEditor; updateDecorations(editor); // 에디터가 변경될 때마다 데코레이션 업데이트 vscode.window.onDidChangeActiveTextEditor( (editor) => { updateDecorations(editor); }, null, context.subscriptions ); context.subscriptions.push( vscode.commands.registerCommand("fold-unfold-smartly.foldUpward", () => { const editor = vscode.window.activeTextEditor; if (!editor) { return; } // 현재 선택된 줄 번호 가져오기 const lineIndex = editor.selection.active.line; console.log(`[SmartFold] foldUpward 명령 실행 - lineIndex: ${lineIndex}`); // lineIndex가 유효한지 확인 if (lineIndex < 0 || lineIndex >= editor.document.lineCount) { console.error(`[SmartFold] 유효하지 않은 lineIndex: ${lineIndex}`); return; } const range = findCurrentToInitialIndentFoldRange( editor.document, lineIndex ); if (range) { const visibleRange = editor.visibleRanges[0]; const startLine = visibleRange.start.line; vscode.commands.executeCommand("editor.fold", { selectionLines: [range.start], }); const newTop = startLine + range.start - range.end + 5; const newStartPosition = new vscode.Position( newTop < 0 ? 0 : newTop, 0 ); editor.revealRange( new vscode.Range(newStartPosition, newStartPosition), vscode.TextEditorRevealType.AtTop ); } }) ); console.log("[SmartFold] 확장 프로그램이 활성화되었습니다."); vscode.window.showInformationMessage( "[SmartFold] 확장 프로그램이 활성화되었습니다." ); } export function deactivate() { console.log("[SmartFold] 비활성화되었습니다."); } ```/ ### tsconfig.json TypeScript config 는 다음과 같다. ```[.linenums.scrollable] { "compilerOptions": { /* Language and Environment */ "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, /* Modules */ "module": "CommonJS" /* Specify what module code is generated. */, "rootDir": "./src" /* Specify the root folder within your source files. */, /* Emit */ "outDir": "./dist" /* Specify an output folder for all emitted files. */, /* Interop Constraints */ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ "strict": true /* Enable all strict type-checking options. */, "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, "include": ["src/**/*"], "exclude": ["node_modules"] } ```/ ### tsc && npx vsce package && npx vsce publish 다음과 같은 명령어로 package 를 만들고 publish 까지 하면 끝. 젤 처음엔 access token 넣으라고 할텐데, 에서 잘 찾아서 넣으면 된다. ```[.linenums] tsc npx vsce package npx vsce publish ```/ ## 구현 된 모습 동영상
## RRA
    https://code.visualstudio.com/api/get-started/your-first-extension
  1. https://marketplace.visualstudio.com/vscode
  2. https://github.com/kipid/fold-unfold-smartly
  3. https://marketplace.visualstudio.com/items?itemName=kipacti.fold-unfold-smartly&ssr=false#overview
반응형