[{"data":1,"prerenderedAt":3112},["ShallowReactive",2],{"post-creating-an-openai-powered-writing-assistant-vs-code-extension":3},{"id":4,"title":5,"body":6,"canonicalUrl":3095,"cover":3096,"date":3097,"description":3098,"draft":3099,"extension":3100,"hashnodeId":3101,"meta":3102,"navigation":561,"path":3103,"seo":3104,"slug":3105,"stem":3105,"tags":3106,"__hash__":3111},"posts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension.md","Creating an OpenAI powered Writing Assistant for VS Code",{"type":7,"value":8,"toc":3083},"minimark",[9,18,23,26,29,36,39,43,66,78,84,90,97,103,107,117,144,150,165,170,186,264,267,273,277,287,344,351,360,700,723,734,740,1133,1136,1142,1145,1149,1155,1163,1300,1306,1336,1355,1389,1395,1607,1613,1616,1620,1623,1626,1644,1649,1670,1675,2713,2716,2722,2725,2729,2745,2894,2901,3028,3031,3035,3038,3055,3063,3070,3073,3079],[10,11,12,13,17],"p",{},"Rabbit holes are many, and as a developer, you keep falling into one or the other during your journey. This is not necessarily a bad thing—granted that it may frustrate you—that is how you learn something extra (the 0.01 of 1.01",[14,15,16],"sup",{},"365","). This is one such story where my urge to create something new pushed me into writing a brand new VS Code extension.",[19,20,22],"h2",{"id":21},"introduction","Introduction",[10,24,25],{},"I've always wondered how a VS Code extension works and what it takes to implement one. Recently this urge got the best of me and I decided to finally create a VS Code extension. But what to build? I like using Hashnode's AI editor for rephrasing texts and other writing assistance, so I thought why not implement a similar functionality for VS Code? Since writing assistance is most useful for a markdown file (which can also work as a blog post), I created a basic writing assistant for markdown (and text) files.",[10,27,28],{},"Here is a simple GIF showcasing how the extension works.",[10,30,31],{},[32,33],"img",{"alt":34,"src":35},"Write Assist AI working gif","\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002Fd8a0ae80-fa3e-4b76-ba45-89146a35ef6b-270734e4f0.gif",[10,37,38],{},"Ready to dive into how I implemented it? Let's get started.",[19,40,42],{"id":41},"getting-started","Getting Started",[10,44,45,46,53,54,59,60,65],{},"Before we can start building the extension, we need to gather and prepare the necessary tools. In this case, the needed tools are node, git, ",[47,48,52],"a",{"href":49,"rel":50},"https:\u002F\u002Fyeoman.io\u002F",[51],"nofollow","yeoman"," and ",[47,55,58],{"href":56,"rel":57},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fgenerator-code",[51],"generator-code",". For a newcomer like myself, ",[47,61,64],{"href":62,"rel":63},"https:\u002F\u002Fcode.visualstudio.com\u002Fapi\u002Fget-started\u002Fyour-first-extension",[51],"this basic tutorial"," is perfect. I recommend going through it to learn the fundamentals.",[10,67,68,69,73,74,77],{},"Run ",[70,71,72],"code",{},"yo code"," command and pick ",[70,75,76],{},"New Extension (js\u002Fts)"," from the choices as shown below",[10,79,80],{},[32,81],{"alt":82,"src":83},"yo code command choices","\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002F103a52d9-c518-4e23-8694-fae49d972fce-1e72801190.png",[10,85,86],{},[32,87],{"alt":88,"src":89},"All steps of the yo code command","\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002F569c6d97-1a09-4c45-8fe9-9e0e9ddc73a8-c9e17c625f.png",[10,91,92,93,96],{},"I haven't selected the ",[70,94,95],{},"webpack"," option yet. We can always do so later on. This is my current directory structure.",[10,98,99],{},[32,100],{"alt":101,"src":102},"Basic directory structure for a VS Code extension","\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002Fefee7119-e8fc-4bdd-9640-9507fc7197ed-d2d2ac73cb.png",[19,104,106],{"id":105},"implementing-the-extension","Implementing the extension",[10,108,109,110,53,113,116],{},"We're mostly interested in the ",[70,111,112],{},"package.json",[70,114,115],{},"extension.ts"," files while building the extension. The important fields in the package.json file are",[118,119,120,128,138],"ol",{},[121,122,123,127],"li",{},[124,125,126],"strong",{},"activationEvents",": When should our extension be activated",[121,129,130,133,134,137],{},[124,131,132],{},"main",": The entry point of the extension code (the entry is in the ",[70,135,136],{},"out"," folder which gets generated when you debug or run the extension)",[121,139,140,143],{},[124,141,142],{},"contributes",": What does this extension contributes to the VS Code commands and settings",[10,145,146],{},[32,147],{"alt":148,"src":149},"package.json fields","\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002F5d4626a4-1d24-4809-9080-03883ff31b23-0a34819095.png",[10,151,152,153,158,159,164],{},"For my extension I wanted an experience similar to the Hashnode AI Editor, so adding commands to the VS Code command palette was not what I was after. What helped me here was the sample extensions directory on ",[47,154,157],{"href":155,"rel":156},"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fvscode-extension-samples\u002F",[51],"GitHub",". Their ",[47,160,163],{"href":161,"rel":162},"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fvscode-extension-samples\u002Ftree\u002Fmain\u002Fcode-actions-sample",[51],"code-actions"," sample was exactly what I had in mind (and it targets only the markdown files).",[166,167,169],"h3",{"id":168},"target-markdown-and-text-files","Target Markdown and Text files",[10,171,172,173,175,176,53,179,182,183,185],{},"To target specific types of files you need to change the ",[70,174,126],{},". Since we want to work only with ",[70,177,178],{},"Markdown",[70,180,181],{},"Text"," files at the moment, this is what my ",[70,184,112],{}," says",[187,188,193],"pre",{"className":189,"code":190,"language":191,"meta":192,"style":192},"language-json shiki shiki-themes github-light github-dark","\u002F\u002F ...\n\"activationEvents\": [\n  \"onLanguage:markdown\",\n  \"onLanguage:plaintext\"\n],\n\"main\": \".\u002Fout\u002Fextension.js\",\n\"contributes\": {},\n\u002F\u002F ...\n","json","",[70,194,195,204,215,224,230,236,250,259],{"__ignoreMap":192},[196,197,200],"span",{"class":198,"line":199},"line",1,[196,201,203],{"class":202},"sJ8bj","\u002F\u002F ...\n",[196,205,207,211],{"class":198,"line":206},2,[196,208,210],{"class":209},"sZZnC","\"activationEvents\"",[196,212,214],{"class":213},"sVt8B",": [\n",[196,216,218,221],{"class":198,"line":217},3,[196,219,220],{"class":209},"  \"onLanguage:markdown\"",[196,222,223],{"class":213},",\n",[196,225,227],{"class":198,"line":226},4,[196,228,229],{"class":209},"  \"onLanguage:plaintext\"\n",[196,231,233],{"class":198,"line":232},5,[196,234,235],{"class":213},"],\n",[196,237,239,242,245,248],{"class":198,"line":238},6,[196,240,241],{"class":209},"\"main\"",[196,243,244],{"class":213},": ",[196,246,247],{"class":209},"\".\u002Fout\u002Fextension.js\"",[196,249,223],{"class":213},[196,251,253,256],{"class":198,"line":252},7,[196,254,255],{"class":209},"\"contributes\"",[196,257,258],{"class":213},": {},\n",[196,260,262],{"class":198,"line":261},8,[196,263,203],{"class":202},[10,265,266],{},"This extension will only get activated for the languages mentioned above.",[10,268,269,270,272],{},"Also, since we don't want any command palette commands, we can remove everything under the ",[70,271,142],{}," key.",[166,274,276],{"id":275},"showing-the-actions-in-the-light-bulb-menu","Showing the actions in the light bulb menu",[10,278,279,280,283,284,286],{},"There is one function called ",[70,281,282],{},"activate"," inside the ",[70,285,115],{}," file which is of interest. This is where you need to write your code. Notice that I've removed all the unnecessary boilerplate code",[187,288,292],{"className":289,"code":290,"language":291,"meta":192,"style":192},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F This method is called when your extension is activated\n\u002F\u002F Your extension is activated the very first time the \n\u002F\u002F command is executed\nexport function activate(context: vscode.ExtensionContext) {}\n","typescript",[70,293,294,299,304,309],{"__ignoreMap":192},[196,295,296],{"class":198,"line":199},[196,297,298],{"class":202},"\u002F\u002F This method is called when your extension is activated\n",[196,300,301],{"class":198,"line":206},[196,302,303],{"class":202},"\u002F\u002F Your extension is activated the very first time the \n",[196,305,306],{"class":198,"line":217},[196,307,308],{"class":202},"\u002F\u002F command is executed\n",[196,310,311,315,318,322,325,329,332,335,338,341],{"class":198,"line":226},[196,312,314],{"class":313},"szBVR","export",[196,316,317],{"class":313}," function",[196,319,321],{"class":320},"sScJk"," activate",[196,323,324],{"class":213},"(",[196,326,328],{"class":327},"s4XuR","context",[196,330,331],{"class":313},":",[196,333,334],{"class":320}," vscode",[196,336,337],{"class":213},".",[196,339,340],{"class":320},"ExtensionContext",[196,342,343],{"class":213},") {}\n",[10,345,346,347,350],{},"There is another complementary function called ",[70,348,349],{},"deactivate"," which can be used if you need to do any kind of resource cleaning before the extension is deactivated.",[10,352,353,354,356,357,359],{},"If you run\u002Fdebug the extension now, and create a new markdown file in the new VS Code window which pops up, you won't notice any difference as there is no palette command, and also there is no code in the ",[70,355,282],{}," function. Let's change that and add the following in the ",[70,358,115],{}," file",[187,361,363],{"className":289,"code":362,"language":291,"meta":192,"style":192},"class MyCodeActionProvider implements vscode.CodeActionProvider {\n  \n  provideCodeActions(\n    document: vscode.TextDocument,\n    range: vscode.Range | vscode.Selection,\n    context: vscode.CodeActionContext,\n    token: vscode.CancellationToken\n  ): vscode.ProviderResult\u003C(vscode.CodeAction | vscode.Command)[]> {\n    console.log('inside the provideCodeActions method');\n    throw new Error('Method not implemented.');\n  }\n}\n\nexport function activate(context: vscode.ExtensionContext) {\n  const actionProvider = vscode.languages.registerCodeActionsProvider(\n    ['markdown', 'plaintext'],\n    new MyCodeActionProvider(),\n    {\n      providedCodeActionKinds: [\n        vscode.CodeActionKind.RefactorRewrite,\n        vscode.CodeActionKind.QuickFix,\n      ],\n    }\n  );\n\n  context.subscriptions.push(actionProvider);\n}\n",[70,364,365,386,391,399,415,441,457,471,508,525,544,550,556,563,587,608,625,636,642,648,654,660,666,672,678,683,695],{"__ignoreMap":192},[196,366,367,370,373,376,378,380,383],{"class":198,"line":199},[196,368,369],{"class":313},"class",[196,371,372],{"class":320}," MyCodeActionProvider",[196,374,375],{"class":313}," implements",[196,377,334],{"class":320},[196,379,337],{"class":213},[196,381,382],{"class":320},"CodeActionProvider",[196,384,385],{"class":213}," {\n",[196,387,388],{"class":198,"line":206},[196,389,390],{"class":213},"  \n",[196,392,393,396],{"class":198,"line":217},[196,394,395],{"class":320},"  provideCodeActions",[196,397,398],{"class":213},"(\n",[196,400,401,404,406,408,410,413],{"class":198,"line":226},[196,402,403],{"class":327},"    document",[196,405,331],{"class":313},[196,407,334],{"class":320},[196,409,337],{"class":213},[196,411,412],{"class":320},"TextDocument",[196,414,223],{"class":213},[196,416,417,420,422,424,426,429,432,434,436,439],{"class":198,"line":232},[196,418,419],{"class":327},"    range",[196,421,331],{"class":313},[196,423,334],{"class":320},[196,425,337],{"class":213},[196,427,428],{"class":320},"Range",[196,430,431],{"class":313}," |",[196,433,334],{"class":320},[196,435,337],{"class":213},[196,437,438],{"class":320},"Selection",[196,440,223],{"class":213},[196,442,443,446,448,450,452,455],{"class":198,"line":238},[196,444,445],{"class":327},"    context",[196,447,331],{"class":313},[196,449,334],{"class":320},[196,451,337],{"class":213},[196,453,454],{"class":320},"CodeActionContext",[196,456,223],{"class":213},[196,458,459,462,464,466,468],{"class":198,"line":252},[196,460,461],{"class":327},"    token",[196,463,331],{"class":313},[196,465,334],{"class":320},[196,467,337],{"class":213},[196,469,470],{"class":320},"CancellationToken\n",[196,472,473,476,478,480,482,485,488,491,493,496,498,500,502,505],{"class":198,"line":261},[196,474,475],{"class":213},"  )",[196,477,331],{"class":313},[196,479,334],{"class":320},[196,481,337],{"class":213},[196,483,484],{"class":320},"ProviderResult",[196,486,487],{"class":213},"\u003C(",[196,489,490],{"class":320},"vscode",[196,492,337],{"class":213},[196,494,495],{"class":320},"CodeAction",[196,497,431],{"class":313},[196,499,334],{"class":320},[196,501,337],{"class":213},[196,503,504],{"class":320},"Command",[196,506,507],{"class":213},")[]> {\n",[196,509,511,514,517,519,522],{"class":198,"line":510},9,[196,512,513],{"class":213},"    console.",[196,515,516],{"class":320},"log",[196,518,324],{"class":213},[196,520,521],{"class":209},"'inside the provideCodeActions method'",[196,523,524],{"class":213},");\n",[196,526,528,531,534,537,539,542],{"class":198,"line":527},10,[196,529,530],{"class":313},"    throw",[196,532,533],{"class":313}," new",[196,535,536],{"class":320}," Error",[196,538,324],{"class":213},[196,540,541],{"class":209},"'Method not implemented.'",[196,543,524],{"class":213},[196,545,547],{"class":198,"line":546},11,[196,548,549],{"class":213},"  }\n",[196,551,553],{"class":198,"line":552},12,[196,554,555],{"class":213},"}\n",[196,557,559],{"class":198,"line":558},13,[196,560,562],{"emptyLinePlaceholder":561},true,"\n",[196,564,566,568,570,572,574,576,578,580,582,584],{"class":198,"line":565},14,[196,567,314],{"class":313},[196,569,317],{"class":313},[196,571,321],{"class":320},[196,573,324],{"class":213},[196,575,328],{"class":327},[196,577,331],{"class":313},[196,579,334],{"class":320},[196,581,337],{"class":213},[196,583,340],{"class":320},[196,585,586],{"class":213},") {\n",[196,588,590,593,597,600,603,606],{"class":198,"line":589},15,[196,591,592],{"class":313},"  const",[196,594,596],{"class":595},"sj4cs"," actionProvider",[196,598,599],{"class":313}," =",[196,601,602],{"class":213}," vscode.languages.",[196,604,605],{"class":320},"registerCodeActionsProvider",[196,607,398],{"class":213},[196,609,611,614,617,620,623],{"class":198,"line":610},16,[196,612,613],{"class":213},"    [",[196,615,616],{"class":209},"'markdown'",[196,618,619],{"class":213},", ",[196,621,622],{"class":209},"'plaintext'",[196,624,235],{"class":213},[196,626,628,631,633],{"class":198,"line":627},17,[196,629,630],{"class":313},"    new",[196,632,372],{"class":320},[196,634,635],{"class":213},"(),\n",[196,637,639],{"class":198,"line":638},18,[196,640,641],{"class":213},"    {\n",[196,643,645],{"class":198,"line":644},19,[196,646,647],{"class":213},"      providedCodeActionKinds: [\n",[196,649,651],{"class":198,"line":650},20,[196,652,653],{"class":213},"        vscode.CodeActionKind.RefactorRewrite,\n",[196,655,657],{"class":198,"line":656},21,[196,658,659],{"class":213},"        vscode.CodeActionKind.QuickFix,\n",[196,661,663],{"class":198,"line":662},22,[196,664,665],{"class":213},"      ],\n",[196,667,669],{"class":198,"line":668},23,[196,670,671],{"class":213},"    }\n",[196,673,675],{"class":198,"line":674},24,[196,676,677],{"class":213},"  );\n",[196,679,681],{"class":198,"line":680},25,[196,682,562],{"emptyLinePlaceholder":561},[196,684,686,689,692],{"class":198,"line":685},26,[196,687,688],{"class":213},"  context.subscriptions.",[196,690,691],{"class":320},"push",[196,693,694],{"class":213},"(actionProvider);\n",[196,696,698],{"class":198,"line":697},27,[196,699,555],{"class":213},[10,701,702,703,706,707,710,711,714,715,718,719,722],{},"What we're doing here is informing VS Code about the kind of code actions we're providing which include ",[70,704,705],{},"RefactorRewrite"," & ",[70,708,709],{},"QuickFix",". The actual ",[70,712,713],{},"\"commands\u002Fcode actions\""," need to be provided by the ",[70,716,717],{},"provideCodeActions"," method of the ",[70,720,721],{},"MyCodeActionProvider"," class. If you debug the extension now you should see the below console log in your original project window's debug console.",[187,724,728],{"className":725,"code":726,"language":727,"meta":192,"style":192},"language-plaintext shiki shiki-themes github-light github-dark","inside the provideCodeActions method\n","plaintext",[70,729,730],{"__ignoreMap":192},[196,731,732],{"class":198,"line":199},[196,733,726],{},[10,735,736,737,739],{},"We're making progress. Replace the ",[70,738,717],{}," method's code with the following",[187,741,743],{"className":289,"code":742,"language":291,"meta":192,"style":192},"provideCodeActions(\n  document: vscode.TextDocument,\n  range: vscode.Range | vscode.Selection,\n  context: vscode.CodeActionContext,\n  token: vscode.CancellationToken\n): vscode.ProviderResult\u003C(vscode.CodeAction | vscode.Command)[]> {\n  \u002F\u002F If there is nothing selected, we won't provide any action\n  if (range.isEmpty) {\n    return;\n  }\n\n  \u002F\u002F supported actions and their kinds\n  const actions = [\n    {\n      id: 'rephrase',\n      title: 'Rephrase selected text',\n      kind: vscode.CodeActionKind.QuickFix,\n    },\n    {\n      id: 'headlines',\n      title: 'Suggest headlines',\n      kind: vscode.CodeActionKind.QuickFix,\n    },\n    {\n      id: 'professional',\n      title: 'Rewrite in professional tone',\n      kind: vscode.CodeActionKind.RefactorRewrite,\n    },\n    {\n      id: 'casual',\n      title: 'Rewrite in casual tone',\n      kind: vscode.CodeActionKind.RefactorRewrite,\n    },\n  ];\n\n  const cActions = [];\n  \u002F\u002F prepare the code actions for the above actions\n  for (const action of actions) {\n    const cAction = new vscode.CodeAction(action.title, action.kind);\n    cAction.command = {\n      command: `my-shiny-extension.${action.id}`,\n      title: action.title,\n      arguments: [action.id],\n    };\n\n    cActions.push(cAction);\n  }\n\n  return cActions;\n}\n",[70,744,745,751,756,767,772,777,798,803,811,819,823,827,832,843,847,857,867,872,877,881,890,899,903,907,911,920,929,934,939,944,954,964,969,974,980,985,996,1002,1025,1046,1056,1078,1084,1090,1096,1101,1112,1117,1122,1128],{"__ignoreMap":192},[196,746,747,749],{"class":198,"line":199},[196,748,717],{"class":320},[196,750,398],{"class":213},[196,752,753],{"class":198,"line":206},[196,754,755],{"class":213},"  document: vscode.TextDocument,\n",[196,757,758,761,764],{"class":198,"line":217},[196,759,760],{"class":213},"  range: vscode.Range ",[196,762,763],{"class":313},"|",[196,765,766],{"class":213}," vscode.Selection,\n",[196,768,769],{"class":198,"line":226},[196,770,771],{"class":213},"  context: vscode.CodeActionContext,\n",[196,773,774],{"class":198,"line":232},[196,775,776],{"class":213},"  token: vscode.CancellationToken\n",[196,778,779,782,785,788,790,793,796],{"class":198,"line":238},[196,780,781],{"class":213},"): vscode.ProviderResult",[196,783,784],{"class":313},"\u003C",[196,786,787],{"class":213},"(vscode.CodeAction ",[196,789,763],{"class":313},[196,791,792],{"class":213}," vscode.Command)[]",[196,794,795],{"class":313},">",[196,797,385],{"class":213},[196,799,800],{"class":198,"line":252},[196,801,802],{"class":202},"  \u002F\u002F If there is nothing selected, we won't provide any action\n",[196,804,805,808],{"class":198,"line":261},[196,806,807],{"class":320},"  if",[196,809,810],{"class":213}," (range.isEmpty) {\n",[196,812,813,816],{"class":198,"line":510},[196,814,815],{"class":313},"    return",[196,817,818],{"class":213},";\n",[196,820,821],{"class":198,"line":527},[196,822,549],{"class":213},[196,824,825],{"class":198,"line":546},[196,826,562],{"emptyLinePlaceholder":561},[196,828,829],{"class":198,"line":552},[196,830,831],{"class":202},"  \u002F\u002F supported actions and their kinds\n",[196,833,834,837,840],{"class":198,"line":558},[196,835,836],{"class":213},"  const actions ",[196,838,839],{"class":313},"=",[196,841,842],{"class":213}," [\n",[196,844,845],{"class":198,"line":565},[196,846,641],{"class":213},[196,848,849,852,855],{"class":198,"line":589},[196,850,851],{"class":213},"      id: ",[196,853,854],{"class":209},"'rephrase'",[196,856,223],{"class":213},[196,858,859,862,865],{"class":198,"line":610},[196,860,861],{"class":213},"      title: ",[196,863,864],{"class":209},"'Rephrase selected text'",[196,866,223],{"class":213},[196,868,869],{"class":198,"line":627},[196,870,871],{"class":213},"      kind: vscode.CodeActionKind.QuickFix,\n",[196,873,874],{"class":198,"line":638},[196,875,876],{"class":213},"    },\n",[196,878,879],{"class":198,"line":644},[196,880,641],{"class":213},[196,882,883,885,888],{"class":198,"line":650},[196,884,851],{"class":213},[196,886,887],{"class":209},"'headlines'",[196,889,223],{"class":213},[196,891,892,894,897],{"class":198,"line":656},[196,893,861],{"class":213},[196,895,896],{"class":209},"'Suggest headlines'",[196,898,223],{"class":213},[196,900,901],{"class":198,"line":662},[196,902,871],{"class":213},[196,904,905],{"class":198,"line":668},[196,906,876],{"class":213},[196,908,909],{"class":198,"line":674},[196,910,641],{"class":213},[196,912,913,915,918],{"class":198,"line":680},[196,914,851],{"class":213},[196,916,917],{"class":209},"'professional'",[196,919,223],{"class":213},[196,921,922,924,927],{"class":198,"line":685},[196,923,861],{"class":213},[196,925,926],{"class":209},"'Rewrite in professional tone'",[196,928,223],{"class":213},[196,930,931],{"class":198,"line":697},[196,932,933],{"class":213},"      kind: vscode.CodeActionKind.RefactorRewrite,\n",[196,935,937],{"class":198,"line":936},28,[196,938,876],{"class":213},[196,940,942],{"class":198,"line":941},29,[196,943,641],{"class":213},[196,945,947,949,952],{"class":198,"line":946},30,[196,948,851],{"class":213},[196,950,951],{"class":209},"'casual'",[196,953,223],{"class":213},[196,955,957,959,962],{"class":198,"line":956},31,[196,958,861],{"class":213},[196,960,961],{"class":209},"'Rewrite in casual tone'",[196,963,223],{"class":213},[196,965,967],{"class":198,"line":966},32,[196,968,933],{"class":213},[196,970,972],{"class":198,"line":971},33,[196,973,876],{"class":213},[196,975,977],{"class":198,"line":976},34,[196,978,979],{"class":213},"  ];\n",[196,981,983],{"class":198,"line":982},35,[196,984,562],{"emptyLinePlaceholder":561},[196,986,988,991,993],{"class":198,"line":987},36,[196,989,990],{"class":213},"  const cActions ",[196,992,839],{"class":313},[196,994,995],{"class":213}," [];\n",[196,997,999],{"class":198,"line":998},37,[196,1000,1001],{"class":202},"  \u002F\u002F prepare the code actions for the above actions\n",[196,1003,1005,1008,1011,1014,1017,1020,1023],{"class":198,"line":1004},38,[196,1006,1007],{"class":320},"  for",[196,1009,1010],{"class":213}," (",[196,1012,1013],{"class":327},"const",[196,1015,1016],{"class":327}," action",[196,1018,1019],{"class":327}," of",[196,1021,1022],{"class":327}," actions",[196,1024,586],{"class":213},[196,1026,1028,1031,1034,1036,1038,1041,1043],{"class":198,"line":1027},39,[196,1029,1030],{"class":313},"    const",[196,1032,1033],{"class":595}," cAction",[196,1035,599],{"class":313},[196,1037,533],{"class":313},[196,1039,1040],{"class":213}," vscode.",[196,1042,495],{"class":320},[196,1044,1045],{"class":213},"(action.title, action.kind);\n",[196,1047,1049,1052,1054],{"class":198,"line":1048},40,[196,1050,1051],{"class":213},"    cAction.command ",[196,1053,839],{"class":313},[196,1055,385],{"class":213},[196,1057,1059,1062,1065,1068,1070,1073,1076],{"class":198,"line":1058},41,[196,1060,1061],{"class":213},"      command: ",[196,1063,1064],{"class":209},"`my-shiny-extension.${",[196,1066,1067],{"class":213},"action",[196,1069,337],{"class":209},[196,1071,1072],{"class":213},"id",[196,1074,1075],{"class":209},"}`",[196,1077,223],{"class":213},[196,1079,1081],{"class":198,"line":1080},42,[196,1082,1083],{"class":213},"      title: action.title,\n",[196,1085,1087],{"class":198,"line":1086},43,[196,1088,1089],{"class":213},"      arguments: [action.id],\n",[196,1091,1093],{"class":198,"line":1092},44,[196,1094,1095],{"class":213},"    };\n",[196,1097,1099],{"class":198,"line":1098},45,[196,1100,562],{"emptyLinePlaceholder":561},[196,1102,1104,1107,1109],{"class":198,"line":1103},46,[196,1105,1106],{"class":213},"    cActions.",[196,1108,691],{"class":320},[196,1110,1111],{"class":213},"(cAction);\n",[196,1113,1115],{"class":198,"line":1114},47,[196,1116,549],{"class":213},[196,1118,1120],{"class":198,"line":1119},48,[196,1121,562],{"emptyLinePlaceholder":561},[196,1123,1125],{"class":198,"line":1124},49,[196,1126,1127],{"class":213},"  return cActions;\n",[196,1129,1131],{"class":198,"line":1130},50,[196,1132,555],{"class":213},[10,1134,1135],{},"Debug\u002Frun the extension now and you should see the above actions in the bulb tooltip when you select some text in a markdown\u002Ftext file.",[10,1137,1138],{},[32,1139],{"alt":1140,"src":1141},"code action window intermediate view","\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002F5b8b0741-8035-46e9-a57d-39e97d9d7af1-90f809ff51.png",[10,1143,1144],{},"Of course, nothing will happen if you click on any of these actions. This is because we've only created the actions, but haven't written any code to handle them.",[166,1146,1148],{"id":1147},"handling-the-code-actions","Handling the Code Actions",[10,1150,1151,1152,1154],{},"To handle the actions we need to register these commands with the VS Code extension context. This can be done inside the ",[70,1153,282],{}," function. Let's do a little bit of refactoring.",[10,1156,1157,1158,1160,1161],{},"Move the actions out of the ",[70,1159,717],{}," method and make it a class property of ",[70,1162,721],{},[187,1164,1166],{"className":289,"code":1165,"language":291,"meta":192,"style":192},"public static readonly actions = [\n  {\n    id: 'rephrase',\n    title: 'Rephrase selected text',\n    kind: vscode.CodeActionKind.QuickFix,\n  },\n  {\n    id: 'headlines',\n    title: 'Suggest headlines',\n    kind: vscode.CodeActionKind.QuickFix,\n  },\n  {\n    id: 'professional',\n    title: 'Rewrite in professional tone',\n    kind: vscode.CodeActionKind.RefactorRewrite,\n  },\n  {\n    id: 'casual',\n    title: 'Rewrite in casual tone',\n    kind: vscode.CodeActionKind.RefactorRewrite,\n  },\n];\n",[70,1167,1168,1177,1182,1191,1200,1205,1210,1214,1222,1230,1234,1238,1242,1250,1258,1263,1267,1271,1279,1287,1291,1295],{"__ignoreMap":192},[196,1169,1170,1173,1175],{"class":198,"line":199},[196,1171,1172],{"class":213},"public static readonly actions ",[196,1174,839],{"class":313},[196,1176,842],{"class":213},[196,1178,1179],{"class":198,"line":206},[196,1180,1181],{"class":213},"  {\n",[196,1183,1184,1187,1189],{"class":198,"line":217},[196,1185,1186],{"class":213},"    id: ",[196,1188,854],{"class":209},[196,1190,223],{"class":213},[196,1192,1193,1196,1198],{"class":198,"line":226},[196,1194,1195],{"class":213},"    title: ",[196,1197,864],{"class":209},[196,1199,223],{"class":213},[196,1201,1202],{"class":198,"line":232},[196,1203,1204],{"class":213},"    kind: vscode.CodeActionKind.QuickFix,\n",[196,1206,1207],{"class":198,"line":238},[196,1208,1209],{"class":213},"  },\n",[196,1211,1212],{"class":198,"line":252},[196,1213,1181],{"class":213},[196,1215,1216,1218,1220],{"class":198,"line":261},[196,1217,1186],{"class":213},[196,1219,887],{"class":209},[196,1221,223],{"class":213},[196,1223,1224,1226,1228],{"class":198,"line":510},[196,1225,1195],{"class":213},[196,1227,896],{"class":209},[196,1229,223],{"class":213},[196,1231,1232],{"class":198,"line":527},[196,1233,1204],{"class":213},[196,1235,1236],{"class":198,"line":546},[196,1237,1209],{"class":213},[196,1239,1240],{"class":198,"line":552},[196,1241,1181],{"class":213},[196,1243,1244,1246,1248],{"class":198,"line":558},[196,1245,1186],{"class":213},[196,1247,917],{"class":209},[196,1249,223],{"class":213},[196,1251,1252,1254,1256],{"class":198,"line":565},[196,1253,1195],{"class":213},[196,1255,926],{"class":209},[196,1257,223],{"class":213},[196,1259,1260],{"class":198,"line":589},[196,1261,1262],{"class":213},"    kind: vscode.CodeActionKind.RefactorRewrite,\n",[196,1264,1265],{"class":198,"line":610},[196,1266,1209],{"class":213},[196,1268,1269],{"class":198,"line":627},[196,1270,1181],{"class":213},[196,1272,1273,1275,1277],{"class":198,"line":638},[196,1274,1186],{"class":213},[196,1276,951],{"class":209},[196,1278,223],{"class":213},[196,1280,1281,1283,1285],{"class":198,"line":644},[196,1282,1195],{"class":213},[196,1284,961],{"class":209},[196,1286,223],{"class":213},[196,1288,1289],{"class":198,"line":650},[196,1290,1262],{"class":213},[196,1292,1293],{"class":198,"line":656},[196,1294,1209],{"class":213},[196,1296,1297],{"class":198,"line":662},[196,1298,1299],{"class":213},"];\n",[10,1301,1302,1303,1305],{},"Change its reference inside the ",[70,1304,717],{}," method to",[187,1307,1309],{"className":289,"code":1308,"language":291,"meta":192,"style":192},"for (const action of MyCodeActionProvider.actions) {\n  \u002F\u002F ...\n}\n",[70,1310,1311,1327,1332],{"__ignoreMap":192},[196,1312,1313,1316,1318,1320,1322,1324],{"class":198,"line":199},[196,1314,1315],{"class":313},"for",[196,1317,1010],{"class":213},[196,1319,1013],{"class":313},[196,1321,1016],{"class":595},[196,1323,1019],{"class":313},[196,1325,1326],{"class":213}," MyCodeActionProvider.actions) {\n",[196,1328,1329],{"class":198,"line":206},[196,1330,1331],{"class":202},"  \u002F\u002F ...\n",[196,1333,1334],{"class":198,"line":217},[196,1335,555],{"class":213},[10,1337,1338,1339,1342,1343,1346,1347,1350,1351,1354],{},"Add a new method ",[70,1340,1341],{},"handleAction"," which will handle the actions when a user clicks on them. The ",[70,1344,1345],{},"actionId"," argument will be passed by the caller. Remember we had passed ",[70,1348,1349],{},"arguments: [action.id]"," while returning the code actions from the ",[70,1352,1353],{},"providecodeActions"," method?",[187,1356,1358],{"className":289,"code":1357,"language":291,"meta":192,"style":192},"handleAction(actionId: string) {\n  console.log(`handleAction for ${actionId}`);\n}\n",[70,1359,1360,1367,1385],{"__ignoreMap":192},[196,1361,1362,1364],{"class":198,"line":199},[196,1363,1341],{"class":320},[196,1365,1366],{"class":213},"(actionId: string) {\n",[196,1368,1369,1372,1374,1376,1379,1381,1383],{"class":198,"line":206},[196,1370,1371],{"class":213},"  console.",[196,1373,516],{"class":320},[196,1375,324],{"class":213},[196,1377,1378],{"class":209},"`handleAction for ${",[196,1380,1345],{"class":213},[196,1382,1075],{"class":209},[196,1384,524],{"class":213},[196,1386,1387],{"class":198,"line":217},[196,1388,555],{"class":213},[10,1390,1391,1392,1394],{},"Now change the ",[70,1393,282],{}," function as shown below",[187,1396,1398],{"className":289,"code":1397,"language":291,"meta":192,"style":192},"export function activate(context: vscode.ExtensionContext) {\n  const myActionProvider = new MyCodeActionProvider();\n  const actionProvider = vscode.languages.registerCodeActionsProvider(\n    ['markdown', 'plaintext'],\n    myActionProvider,\n    {\n      providedCodeActionKinds: [\n        vscode.CodeActionKind.RefactorRewrite,\n        vscode.CodeActionKind.QuickFix,\n      ],\n    }\n  );\n\n  context.subscriptions.push(actionProvider);\n  for (const action of MyCodeActionProvider.actions) {\n    context.subscriptions.push(\n      \u002F\u002F use the same id which we used in the command field \n      \u002F\u002F of the code actions\n      vscode.commands.registerCommand(\n        `my-shiny-extension.${action.id}`,\n        (args) => myActionProvider.handleAction(args)\n      )\n    );\n  }\n}\n",[70,1399,1400,1422,1438,1452,1464,1469,1473,1477,1481,1485,1489,1493,1497,1501,1509,1523,1532,1537,1542,1552,1567,1589,1594,1599,1603],{"__ignoreMap":192},[196,1401,1402,1404,1406,1408,1410,1412,1414,1416,1418,1420],{"class":198,"line":199},[196,1403,314],{"class":313},[196,1405,317],{"class":313},[196,1407,321],{"class":320},[196,1409,324],{"class":213},[196,1411,328],{"class":327},[196,1413,331],{"class":313},[196,1415,334],{"class":320},[196,1417,337],{"class":213},[196,1419,340],{"class":320},[196,1421,586],{"class":213},[196,1423,1424,1426,1429,1431,1433,1435],{"class":198,"line":206},[196,1425,592],{"class":313},[196,1427,1428],{"class":595}," myActionProvider",[196,1430,599],{"class":313},[196,1432,533],{"class":313},[196,1434,372],{"class":320},[196,1436,1437],{"class":213},"();\n",[196,1439,1440,1442,1444,1446,1448,1450],{"class":198,"line":217},[196,1441,592],{"class":313},[196,1443,596],{"class":595},[196,1445,599],{"class":313},[196,1447,602],{"class":213},[196,1449,605],{"class":320},[196,1451,398],{"class":213},[196,1453,1454,1456,1458,1460,1462],{"class":198,"line":226},[196,1455,613],{"class":213},[196,1457,616],{"class":209},[196,1459,619],{"class":213},[196,1461,622],{"class":209},[196,1463,235],{"class":213},[196,1465,1466],{"class":198,"line":232},[196,1467,1468],{"class":213},"    myActionProvider,\n",[196,1470,1471],{"class":198,"line":238},[196,1472,641],{"class":213},[196,1474,1475],{"class":198,"line":252},[196,1476,647],{"class":213},[196,1478,1479],{"class":198,"line":261},[196,1480,653],{"class":213},[196,1482,1483],{"class":198,"line":510},[196,1484,659],{"class":213},[196,1486,1487],{"class":198,"line":527},[196,1488,665],{"class":213},[196,1490,1491],{"class":198,"line":546},[196,1492,671],{"class":213},[196,1494,1495],{"class":198,"line":552},[196,1496,677],{"class":213},[196,1498,1499],{"class":198,"line":558},[196,1500,562],{"emptyLinePlaceholder":561},[196,1502,1503,1505,1507],{"class":198,"line":565},[196,1504,688],{"class":213},[196,1506,691],{"class":320},[196,1508,694],{"class":213},[196,1510,1511,1513,1515,1517,1519,1521],{"class":198,"line":589},[196,1512,1007],{"class":313},[196,1514,1010],{"class":213},[196,1516,1013],{"class":313},[196,1518,1016],{"class":595},[196,1520,1019],{"class":313},[196,1522,1326],{"class":213},[196,1524,1525,1528,1530],{"class":198,"line":610},[196,1526,1527],{"class":213},"    context.subscriptions.",[196,1529,691],{"class":320},[196,1531,398],{"class":213},[196,1533,1534],{"class":198,"line":627},[196,1535,1536],{"class":202},"      \u002F\u002F use the same id which we used in the command field \n",[196,1538,1539],{"class":198,"line":638},[196,1540,1541],{"class":202},"      \u002F\u002F of the code actions\n",[196,1543,1544,1547,1550],{"class":198,"line":644},[196,1545,1546],{"class":213},"      vscode.commands.",[196,1548,1549],{"class":320},"registerCommand",[196,1551,398],{"class":213},[196,1553,1554,1557,1559,1561,1563,1565],{"class":198,"line":650},[196,1555,1556],{"class":209},"        `my-shiny-extension.${",[196,1558,1067],{"class":213},[196,1560,337],{"class":209},[196,1562,1072],{"class":213},[196,1564,1075],{"class":209},[196,1566,223],{"class":213},[196,1568,1569,1572,1575,1578,1581,1584,1586],{"class":198,"line":656},[196,1570,1571],{"class":213},"        (",[196,1573,1574],{"class":327},"args",[196,1576,1577],{"class":213},") ",[196,1579,1580],{"class":313},"=>",[196,1582,1583],{"class":213}," myActionProvider.",[196,1585,1341],{"class":320},[196,1587,1588],{"class":213},"(args)\n",[196,1590,1591],{"class":198,"line":662},[196,1592,1593],{"class":213},"      )\n",[196,1595,1596],{"class":198,"line":668},[196,1597,1598],{"class":213},"    );\n",[196,1600,1601],{"class":198,"line":674},[196,1602,549],{"class":213},[196,1604,1605],{"class":198,"line":680},[196,1606,555],{"class":213},[10,1608,1609,1610,1612],{},"For all the actions which we support, we're registering a corresponding command with the VS Code extension context. The command id that we use here must match the command id which we returned from the ",[70,1611,717],{}," method.",[10,1614,1615],{},"If we run\u002Fdebug the extension now and click any of our actions from the light bulb menu we should see the corresponding console log in the debug console.",[166,1617,1619],{"id":1618},"integrating-with-the-openai-apis","Integrating with the OpenAI APIs",[10,1621,1622],{},"Now the only thing remaining is: using the OpenAI APIs to make changes to any written text. Let's get it over with.",[10,1624,1625],{},"Add the OpenAI library to the codebase",[187,1627,1631],{"className":1628,"code":1629,"language":1630,"meta":192,"style":192},"language-bash shiki shiki-themes github-light github-dark","yarn add openai\n","bash",[70,1632,1633],{"__ignoreMap":192},[196,1634,1635,1638,1641],{"class":198,"line":199},[196,1636,1637],{"class":320},"yarn",[196,1639,1640],{"class":209}," add",[196,1642,1643],{"class":209}," openai\n",[10,1645,1646,1647,359],{},"Import it into the ",[70,1648,115],{},[187,1650,1652],{"className":289,"code":1651,"language":291,"meta":192,"style":192},"import { OpenAIApi, Configuration } from 'openai';\n",[70,1653,1654],{"__ignoreMap":192},[196,1655,1656,1659,1662,1665,1668],{"class":198,"line":199},[196,1657,1658],{"class":313},"import",[196,1660,1661],{"class":213}," { OpenAIApi, Configuration } ",[196,1663,1664],{"class":313},"from",[196,1666,1667],{"class":209}," 'openai'",[196,1669,818],{"class":213},[10,1671,1672,1673,739],{},"And replace the ",[70,1674,1341],{},[187,1676,1678],{"className":289,"code":1677,"language":291,"meta":192,"style":192},"async handleAction(actionId: string) {\n  const editor = vscode.window.activeTextEditor;\n  if (\n    !editor ||\n    editor.selection.isEmpty ||\n    !['rephrase', 'headlines', 'professional', 'casual'].includes(actionId)\n  ) {\n    \u002F\u002F return if no active editor, or no active selection \n    \u002F\u002F or if unsupported actionId passed\n    return;\n  }\n\n  \u002F\u002F Create the OpenAI Service\n  const openAiSvc = new OpenAIApi(\n    new Configuration({\n      apiKey: '\u003Cyour_open_ai_api_key>',\n    })\n  );\n\n  \u002F\u002F Get the currently selected text\n  const text = editor.document.getText(editor.selection);\n  \u002F\u002F current selection range\n  let currRange = editor.selection;\n\n  try {\n    \u002F\u002F Adding a filler\u002Floading text before making the API call\n    const fillerText = '\\n\\nThinking...';\n    editor\n      .edit((editBuilder) => {\n        \u002F\u002F insert the filler text after the current selection end\n        editBuilder.insert(currRange.end, fillerText);\n      })\n      .then((success) => {\n        if (success) {\n          \u002F\u002F Select the filler text now\n          editor.selection = new vscode.Selection(\n            editor.selection.end.line,\n            0,\n            editor.selection.end.line,\n            editor.selection.end.character\n          );\n\n          \u002F\u002F store this new selection range\n          currRange = editor.selection;\n        }\n      });\n\n    \u002F\u002F Create the prompt prefix based on the action id\n    let promptPrefix = '';\n    switch (actionId) {\n      case 'rephrase':\n        promptPrefix =\n          'Rephrase the following text and make the sentences more clear and readable';\n        break;\n      case 'headlines':\n        promptPrefix = 'Suggest some short headlines for the following text';\n        break;\n      case 'professional':\n        promptPrefix =\n          'Make the following text better and rewrite it in a professional tone';\n        break;\n      case 'casual':\n        promptPrefix =\n          'Make the following text better and rewrite it in a casual tone';\n        break;\n    }\n\n    \u002F\u002F Make the OpenAI API Call using the desired model and configs\n    \u002F* eslint-disable @typescript-eslint\u002Fnaming-convention *\u002F\n    const response = await openAiSvc.createCompletion({\n      model: 'text-davinci-003',\n      prompt: `${promptPrefix}:\\n\\n${text}\\n\\n`,\n      temperature: 0.3,\n      max_tokens: 500,\n      frequency_penalty: 0.0,\n      presence_penalty: 0.0,\n      n: 1,\n    });\n    \u002F* eslint-enable @typescript-eslint\u002Fnaming-convention *\u002F\n\n    \u002F\u002F We'd reuqested for only one result, use that\n    let result = response.data.choices[0].text;\n    editor\n      .edit((editBuilder) => {\n        if (result) {\n          \u002F\u002F replace the filler text with the actual result\n          editBuilder.replace(\n            new vscode.Range(currRange.start, currRange.end),\n            result.trim()\n          );\n        }\n      })\n      .then((success) => {\n        if (success) {\n          \u002F\u002F Select the resulting text (the text can be longer\n          \u002F\u002F and span over multiple lines, so we treat it \n          \u002F\u002F appropriately to make a complete selection)\n          editor.selection = new vscode.Selection(\n            currRange.start.line,\n            currRange.start.character,\n            currRange.end.line,\n            editor.document.lineAt(currRange.end.line).text.length\n          );\n\n          return;\n        }\n      });\n  } catch (error) {\n    console.error(error);\n  }\n\n  \u002F\u002F In case of API error, show an error text instead\n  editor.edit((editBuilder) => {\n    editor.selection = new vscode.Selection(currRange.start, currRange.end);\n    editBuilder.replace(editor.selection, 'Failed to process...');\n  }):\n}\n",[70,1679,1680,1689,1701,1708,1719,1726,1756,1761,1766,1771,1777,1781,1785,1790,1806,1816,1826,1831,1835,1839,1844,1862,1867,1880,1884,1891,1896,1916,1921,1941,1946,1957,1962,1980,1988,1993,2008,2013,2020,2024,2029,2034,2038,2043,2052,2057,2062,2066,2071,2086,2094,2106,2115,2123,2131,2141,2153,2160,2170,2177,2185,2192,2202,2209,2217,2224,2229,2234,2240,2246,2267,2278,2311,2322,2333,2344,2354,2365,2371,2377,2382,2388,2407,2412,2429,2437,2443,2454,2467,2479,2484,2489,2494,2511,2518,2524,2530,2536,2551,2557,2563,2569,2584,2589,2594,2602,2607,2612,2624,2635,2640,2645,2651,2669,2686,2702,2708],{"__ignoreMap":192},[196,1681,1682,1685,1687],{"class":198,"line":199},[196,1683,1684],{"class":213},"async ",[196,1686,1341],{"class":320},[196,1688,1366],{"class":213},[196,1690,1691,1693,1696,1698],{"class":198,"line":206},[196,1692,592],{"class":313},[196,1694,1695],{"class":595}," editor",[196,1697,599],{"class":313},[196,1699,1700],{"class":213}," vscode.window.activeTextEditor;\n",[196,1702,1703,1705],{"class":198,"line":217},[196,1704,807],{"class":313},[196,1706,1707],{"class":213}," (\n",[196,1709,1710,1713,1716],{"class":198,"line":226},[196,1711,1712],{"class":313},"    !",[196,1714,1715],{"class":213},"editor ",[196,1717,1718],{"class":313},"||\n",[196,1720,1721,1724],{"class":198,"line":232},[196,1722,1723],{"class":213},"    editor.selection.isEmpty ",[196,1725,1718],{"class":313},[196,1727,1728,1730,1733,1735,1737,1739,1741,1743,1745,1747,1750,1753],{"class":198,"line":238},[196,1729,1712],{"class":313},[196,1731,1732],{"class":213},"[",[196,1734,854],{"class":209},[196,1736,619],{"class":213},[196,1738,887],{"class":209},[196,1740,619],{"class":213},[196,1742,917],{"class":209},[196,1744,619],{"class":213},[196,1746,951],{"class":209},[196,1748,1749],{"class":213},"].",[196,1751,1752],{"class":320},"includes",[196,1754,1755],{"class":213},"(actionId)\n",[196,1757,1758],{"class":198,"line":252},[196,1759,1760],{"class":213},"  ) {\n",[196,1762,1763],{"class":198,"line":261},[196,1764,1765],{"class":202},"    \u002F\u002F return if no active editor, or no active selection \n",[196,1767,1768],{"class":198,"line":510},[196,1769,1770],{"class":202},"    \u002F\u002F or if unsupported actionId passed\n",[196,1772,1773,1775],{"class":198,"line":527},[196,1774,815],{"class":313},[196,1776,818],{"class":213},[196,1778,1779],{"class":198,"line":546},[196,1780,549],{"class":213},[196,1782,1783],{"class":198,"line":552},[196,1784,562],{"emptyLinePlaceholder":561},[196,1786,1787],{"class":198,"line":558},[196,1788,1789],{"class":202},"  \u002F\u002F Create the OpenAI Service\n",[196,1791,1792,1794,1797,1799,1801,1804],{"class":198,"line":565},[196,1793,592],{"class":313},[196,1795,1796],{"class":595}," openAiSvc",[196,1798,599],{"class":313},[196,1800,533],{"class":313},[196,1802,1803],{"class":320}," OpenAIApi",[196,1805,398],{"class":213},[196,1807,1808,1810,1813],{"class":198,"line":589},[196,1809,630],{"class":313},[196,1811,1812],{"class":320}," Configuration",[196,1814,1815],{"class":213},"({\n",[196,1817,1818,1821,1824],{"class":198,"line":610},[196,1819,1820],{"class":213},"      apiKey: ",[196,1822,1823],{"class":209},"'\u003Cyour_open_ai_api_key>'",[196,1825,223],{"class":213},[196,1827,1828],{"class":198,"line":627},[196,1829,1830],{"class":213},"    })\n",[196,1832,1833],{"class":198,"line":638},[196,1834,677],{"class":213},[196,1836,1837],{"class":198,"line":644},[196,1838,562],{"emptyLinePlaceholder":561},[196,1840,1841],{"class":198,"line":650},[196,1842,1843],{"class":202},"  \u002F\u002F Get the currently selected text\n",[196,1845,1846,1848,1851,1853,1856,1859],{"class":198,"line":656},[196,1847,592],{"class":313},[196,1849,1850],{"class":595}," text",[196,1852,599],{"class":313},[196,1854,1855],{"class":213}," editor.document.",[196,1857,1858],{"class":320},"getText",[196,1860,1861],{"class":213},"(editor.selection);\n",[196,1863,1864],{"class":198,"line":662},[196,1865,1866],{"class":202},"  \u002F\u002F current selection range\n",[196,1868,1869,1872,1875,1877],{"class":198,"line":668},[196,1870,1871],{"class":313},"  let",[196,1873,1874],{"class":213}," currRange ",[196,1876,839],{"class":313},[196,1878,1879],{"class":213}," editor.selection;\n",[196,1881,1882],{"class":198,"line":674},[196,1883,562],{"emptyLinePlaceholder":561},[196,1885,1886,1889],{"class":198,"line":680},[196,1887,1888],{"class":313},"  try",[196,1890,385],{"class":213},[196,1892,1893],{"class":198,"line":685},[196,1894,1895],{"class":202},"    \u002F\u002F Adding a filler\u002Floading text before making the API call\n",[196,1897,1898,1900,1903,1905,1908,1911,1914],{"class":198,"line":697},[196,1899,1030],{"class":313},[196,1901,1902],{"class":595}," fillerText",[196,1904,599],{"class":313},[196,1906,1907],{"class":209}," '",[196,1909,1910],{"class":595},"\\n\\n",[196,1912,1913],{"class":209},"Thinking...'",[196,1915,818],{"class":213},[196,1917,1918],{"class":198,"line":936},[196,1919,1920],{"class":213},"    editor\n",[196,1922,1923,1926,1929,1932,1935,1937,1939],{"class":198,"line":941},[196,1924,1925],{"class":213},"      .",[196,1927,1928],{"class":320},"edit",[196,1930,1931],{"class":213},"((",[196,1933,1934],{"class":327},"editBuilder",[196,1936,1577],{"class":213},[196,1938,1580],{"class":313},[196,1940,385],{"class":213},[196,1942,1943],{"class":198,"line":946},[196,1944,1945],{"class":202},"        \u002F\u002F insert the filler text after the current selection end\n",[196,1947,1948,1951,1954],{"class":198,"line":956},[196,1949,1950],{"class":213},"        editBuilder.",[196,1952,1953],{"class":320},"insert",[196,1955,1956],{"class":213},"(currRange.end, fillerText);\n",[196,1958,1959],{"class":198,"line":966},[196,1960,1961],{"class":213},"      })\n",[196,1963,1964,1966,1969,1971,1974,1976,1978],{"class":198,"line":971},[196,1965,1925],{"class":213},[196,1967,1968],{"class":320},"then",[196,1970,1931],{"class":213},[196,1972,1973],{"class":327},"success",[196,1975,1577],{"class":213},[196,1977,1580],{"class":313},[196,1979,385],{"class":213},[196,1981,1982,1985],{"class":198,"line":976},[196,1983,1984],{"class":313},"        if",[196,1986,1987],{"class":213}," (success) {\n",[196,1989,1990],{"class":198,"line":982},[196,1991,1992],{"class":202},"          \u002F\u002F Select the filler text now\n",[196,1994,1995,1998,2000,2002,2004,2006],{"class":198,"line":987},[196,1996,1997],{"class":213},"          editor.selection ",[196,1999,839],{"class":313},[196,2001,533],{"class":313},[196,2003,1040],{"class":213},[196,2005,438],{"class":320},[196,2007,398],{"class":213},[196,2009,2010],{"class":198,"line":998},[196,2011,2012],{"class":213},"            editor.selection.end.line,\n",[196,2014,2015,2018],{"class":198,"line":1004},[196,2016,2017],{"class":595},"            0",[196,2019,223],{"class":213},[196,2021,2022],{"class":198,"line":1027},[196,2023,2012],{"class":213},[196,2025,2026],{"class":198,"line":1048},[196,2027,2028],{"class":213},"            editor.selection.end.character\n",[196,2030,2031],{"class":198,"line":1058},[196,2032,2033],{"class":213},"          );\n",[196,2035,2036],{"class":198,"line":1080},[196,2037,562],{"emptyLinePlaceholder":561},[196,2039,2040],{"class":198,"line":1086},[196,2041,2042],{"class":202},"          \u002F\u002F store this new selection range\n",[196,2044,2045,2048,2050],{"class":198,"line":1092},[196,2046,2047],{"class":213},"          currRange ",[196,2049,839],{"class":313},[196,2051,1879],{"class":213},[196,2053,2054],{"class":198,"line":1098},[196,2055,2056],{"class":213},"        }\n",[196,2058,2059],{"class":198,"line":1103},[196,2060,2061],{"class":213},"      });\n",[196,2063,2064],{"class":198,"line":1114},[196,2065,562],{"emptyLinePlaceholder":561},[196,2067,2068],{"class":198,"line":1119},[196,2069,2070],{"class":202},"    \u002F\u002F Create the prompt prefix based on the action id\n",[196,2072,2073,2076,2079,2081,2084],{"class":198,"line":1124},[196,2074,2075],{"class":313},"    let",[196,2077,2078],{"class":213}," promptPrefix ",[196,2080,839],{"class":313},[196,2082,2083],{"class":209}," ''",[196,2085,818],{"class":213},[196,2087,2088,2091],{"class":198,"line":1130},[196,2089,2090],{"class":313},"    switch",[196,2092,2093],{"class":213}," (actionId) {\n",[196,2095,2097,2100,2103],{"class":198,"line":2096},51,[196,2098,2099],{"class":313},"      case",[196,2101,2102],{"class":209}," 'rephrase'",[196,2104,2105],{"class":213},":\n",[196,2107,2109,2112],{"class":198,"line":2108},52,[196,2110,2111],{"class":213},"        promptPrefix ",[196,2113,2114],{"class":313},"=\n",[196,2116,2118,2121],{"class":198,"line":2117},53,[196,2119,2120],{"class":209},"          'Rephrase the following text and make the sentences more clear and readable'",[196,2122,818],{"class":213},[196,2124,2126,2129],{"class":198,"line":2125},54,[196,2127,2128],{"class":313},"        break",[196,2130,818],{"class":213},[196,2132,2134,2136,2139],{"class":198,"line":2133},55,[196,2135,2099],{"class":313},[196,2137,2138],{"class":209}," 'headlines'",[196,2140,2105],{"class":213},[196,2142,2144,2146,2148,2151],{"class":198,"line":2143},56,[196,2145,2111],{"class":213},[196,2147,839],{"class":313},[196,2149,2150],{"class":209}," 'Suggest some short headlines for the following text'",[196,2152,818],{"class":213},[196,2154,2156,2158],{"class":198,"line":2155},57,[196,2157,2128],{"class":313},[196,2159,818],{"class":213},[196,2161,2163,2165,2168],{"class":198,"line":2162},58,[196,2164,2099],{"class":313},[196,2166,2167],{"class":209}," 'professional'",[196,2169,2105],{"class":213},[196,2171,2173,2175],{"class":198,"line":2172},59,[196,2174,2111],{"class":213},[196,2176,2114],{"class":313},[196,2178,2180,2183],{"class":198,"line":2179},60,[196,2181,2182],{"class":209},"          'Make the following text better and rewrite it in a professional tone'",[196,2184,818],{"class":213},[196,2186,2188,2190],{"class":198,"line":2187},61,[196,2189,2128],{"class":313},[196,2191,818],{"class":213},[196,2193,2195,2197,2200],{"class":198,"line":2194},62,[196,2196,2099],{"class":313},[196,2198,2199],{"class":209}," 'casual'",[196,2201,2105],{"class":213},[196,2203,2205,2207],{"class":198,"line":2204},63,[196,2206,2111],{"class":213},[196,2208,2114],{"class":313},[196,2210,2212,2215],{"class":198,"line":2211},64,[196,2213,2214],{"class":209},"          'Make the following text better and rewrite it in a casual tone'",[196,2216,818],{"class":213},[196,2218,2220,2222],{"class":198,"line":2219},65,[196,2221,2128],{"class":313},[196,2223,818],{"class":213},[196,2225,2227],{"class":198,"line":2226},66,[196,2228,671],{"class":213},[196,2230,2232],{"class":198,"line":2231},67,[196,2233,562],{"emptyLinePlaceholder":561},[196,2235,2237],{"class":198,"line":2236},68,[196,2238,2239],{"class":202},"    \u002F\u002F Make the OpenAI API Call using the desired model and configs\n",[196,2241,2243],{"class":198,"line":2242},69,[196,2244,2245],{"class":202},"    \u002F* eslint-disable @typescript-eslint\u002Fnaming-convention *\u002F\n",[196,2247,2249,2251,2254,2256,2259,2262,2265],{"class":198,"line":2248},70,[196,2250,1030],{"class":313},[196,2252,2253],{"class":595}," response",[196,2255,599],{"class":313},[196,2257,2258],{"class":313}," await",[196,2260,2261],{"class":213}," openAiSvc.",[196,2263,2264],{"class":320},"createCompletion",[196,2266,1815],{"class":213},[196,2268,2270,2273,2276],{"class":198,"line":2269},71,[196,2271,2272],{"class":213},"      model: ",[196,2274,2275],{"class":209},"'text-davinci-003'",[196,2277,223],{"class":213},[196,2279,2281,2284,2287,2290,2293,2295,2298,2301,2304,2306,2309],{"class":198,"line":2280},72,[196,2282,2283],{"class":213},"      prompt: ",[196,2285,2286],{"class":209},"`${",[196,2288,2289],{"class":213},"promptPrefix",[196,2291,2292],{"class":209},"}:",[196,2294,1910],{"class":595},[196,2296,2297],{"class":209},"${",[196,2299,2300],{"class":213},"text",[196,2302,2303],{"class":209},"}",[196,2305,1910],{"class":595},[196,2307,2308],{"class":209},"`",[196,2310,223],{"class":213},[196,2312,2314,2317,2320],{"class":198,"line":2313},73,[196,2315,2316],{"class":213},"      temperature: ",[196,2318,2319],{"class":595},"0.3",[196,2321,223],{"class":213},[196,2323,2325,2328,2331],{"class":198,"line":2324},74,[196,2326,2327],{"class":213},"      max_tokens: ",[196,2329,2330],{"class":595},"500",[196,2332,223],{"class":213},[196,2334,2336,2339,2342],{"class":198,"line":2335},75,[196,2337,2338],{"class":213},"      frequency_penalty: ",[196,2340,2341],{"class":595},"0.0",[196,2343,223],{"class":213},[196,2345,2347,2350,2352],{"class":198,"line":2346},76,[196,2348,2349],{"class":213},"      presence_penalty: ",[196,2351,2341],{"class":595},[196,2353,223],{"class":213},[196,2355,2357,2360,2363],{"class":198,"line":2356},77,[196,2358,2359],{"class":213},"      n: ",[196,2361,2362],{"class":595},"1",[196,2364,223],{"class":213},[196,2366,2368],{"class":198,"line":2367},78,[196,2369,2370],{"class":213},"    });\n",[196,2372,2374],{"class":198,"line":2373},79,[196,2375,2376],{"class":202},"    \u002F* eslint-enable @typescript-eslint\u002Fnaming-convention *\u002F\n",[196,2378,2380],{"class":198,"line":2379},80,[196,2381,562],{"emptyLinePlaceholder":561},[196,2383,2385],{"class":198,"line":2384},81,[196,2386,2387],{"class":202},"    \u002F\u002F We'd reuqested for only one result, use that\n",[196,2389,2391,2393,2396,2398,2401,2404],{"class":198,"line":2390},82,[196,2392,2075],{"class":313},[196,2394,2395],{"class":213}," result ",[196,2397,839],{"class":313},[196,2399,2400],{"class":213}," response.data.choices[",[196,2402,2403],{"class":595},"0",[196,2405,2406],{"class":213},"].text;\n",[196,2408,2410],{"class":198,"line":2409},83,[196,2411,1920],{"class":213},[196,2413,2415,2417,2419,2421,2423,2425,2427],{"class":198,"line":2414},84,[196,2416,1925],{"class":213},[196,2418,1928],{"class":320},[196,2420,1931],{"class":213},[196,2422,1934],{"class":327},[196,2424,1577],{"class":213},[196,2426,1580],{"class":313},[196,2428,385],{"class":213},[196,2430,2432,2434],{"class":198,"line":2431},85,[196,2433,1984],{"class":313},[196,2435,2436],{"class":213}," (result) {\n",[196,2438,2440],{"class":198,"line":2439},86,[196,2441,2442],{"class":202},"          \u002F\u002F replace the filler text with the actual result\n",[196,2444,2446,2449,2452],{"class":198,"line":2445},87,[196,2447,2448],{"class":213},"          editBuilder.",[196,2450,2451],{"class":320},"replace",[196,2453,398],{"class":213},[196,2455,2457,2460,2462,2464],{"class":198,"line":2456},88,[196,2458,2459],{"class":313},"            new",[196,2461,1040],{"class":213},[196,2463,428],{"class":320},[196,2465,2466],{"class":213},"(currRange.start, currRange.end),\n",[196,2468,2470,2473,2476],{"class":198,"line":2469},89,[196,2471,2472],{"class":213},"            result.",[196,2474,2475],{"class":320},"trim",[196,2477,2478],{"class":213},"()\n",[196,2480,2482],{"class":198,"line":2481},90,[196,2483,2033],{"class":213},[196,2485,2487],{"class":198,"line":2486},91,[196,2488,2056],{"class":213},[196,2490,2492],{"class":198,"line":2491},92,[196,2493,1961],{"class":213},[196,2495,2497,2499,2501,2503,2505,2507,2509],{"class":198,"line":2496},93,[196,2498,1925],{"class":213},[196,2500,1968],{"class":320},[196,2502,1931],{"class":213},[196,2504,1973],{"class":327},[196,2506,1577],{"class":213},[196,2508,1580],{"class":313},[196,2510,385],{"class":213},[196,2512,2514,2516],{"class":198,"line":2513},94,[196,2515,1984],{"class":313},[196,2517,1987],{"class":213},[196,2519,2521],{"class":198,"line":2520},95,[196,2522,2523],{"class":202},"          \u002F\u002F Select the resulting text (the text can be longer\n",[196,2525,2527],{"class":198,"line":2526},96,[196,2528,2529],{"class":202},"          \u002F\u002F and span over multiple lines, so we treat it \n",[196,2531,2533],{"class":198,"line":2532},97,[196,2534,2535],{"class":202},"          \u002F\u002F appropriately to make a complete selection)\n",[196,2537,2539,2541,2543,2545,2547,2549],{"class":198,"line":2538},98,[196,2540,1997],{"class":213},[196,2542,839],{"class":313},[196,2544,533],{"class":313},[196,2546,1040],{"class":213},[196,2548,438],{"class":320},[196,2550,398],{"class":213},[196,2552,2554],{"class":198,"line":2553},99,[196,2555,2556],{"class":213},"            currRange.start.line,\n",[196,2558,2560],{"class":198,"line":2559},100,[196,2561,2562],{"class":213},"            currRange.start.character,\n",[196,2564,2566],{"class":198,"line":2565},101,[196,2567,2568],{"class":213},"            currRange.end.line,\n",[196,2570,2572,2575,2578,2581],{"class":198,"line":2571},102,[196,2573,2574],{"class":213},"            editor.document.",[196,2576,2577],{"class":320},"lineAt",[196,2579,2580],{"class":213},"(currRange.end.line).text.",[196,2582,2583],{"class":595},"length\n",[196,2585,2587],{"class":198,"line":2586},103,[196,2588,2033],{"class":213},[196,2590,2592],{"class":198,"line":2591},104,[196,2593,562],{"emptyLinePlaceholder":561},[196,2595,2597,2600],{"class":198,"line":2596},105,[196,2598,2599],{"class":313},"          return",[196,2601,818],{"class":213},[196,2603,2605],{"class":198,"line":2604},106,[196,2606,2056],{"class":213},[196,2608,2610],{"class":198,"line":2609},107,[196,2611,2061],{"class":213},[196,2613,2615,2618,2621],{"class":198,"line":2614},108,[196,2616,2617],{"class":213},"  } ",[196,2619,2620],{"class":313},"catch",[196,2622,2623],{"class":213}," (error) {\n",[196,2625,2627,2629,2632],{"class":198,"line":2626},109,[196,2628,513],{"class":213},[196,2630,2631],{"class":320},"error",[196,2633,2634],{"class":213},"(error);\n",[196,2636,2638],{"class":198,"line":2637},110,[196,2639,549],{"class":213},[196,2641,2643],{"class":198,"line":2642},111,[196,2644,562],{"emptyLinePlaceholder":561},[196,2646,2648],{"class":198,"line":2647},112,[196,2649,2650],{"class":202},"  \u002F\u002F In case of API error, show an error text instead\n",[196,2652,2654,2657,2659,2661,2663,2665,2667],{"class":198,"line":2653},113,[196,2655,2656],{"class":213},"  editor.",[196,2658,1928],{"class":320},[196,2660,1931],{"class":213},[196,2662,1934],{"class":327},[196,2664,1577],{"class":213},[196,2666,1580],{"class":313},[196,2668,385],{"class":213},[196,2670,2672,2675,2677,2679,2681,2683],{"class":198,"line":2671},114,[196,2673,2674],{"class":213},"    editor.selection ",[196,2676,839],{"class":313},[196,2678,533],{"class":313},[196,2680,1040],{"class":213},[196,2682,438],{"class":320},[196,2684,2685],{"class":213},"(currRange.start, currRange.end);\n",[196,2687,2689,2692,2694,2697,2700],{"class":198,"line":2688},115,[196,2690,2691],{"class":213},"    editBuilder.",[196,2693,2451],{"class":320},[196,2695,2696],{"class":213},"(editor.selection, ",[196,2698,2699],{"class":209},"'Failed to process...'",[196,2701,524],{"class":213},[196,2703,2705],{"class":198,"line":2704},116,[196,2706,2707],{"class":213},"  }):\n",[196,2709,2711],{"class":198,"line":2710},117,[196,2712,555],{"class":213},[10,2714,2715],{},"And we're done with the code. If you run\u002Fdebug the extension you should see appropriate text replacements for your text. Running it on a couple of my sentences gives me the following results",[10,2717,2718],{},[32,2719],{"alt":2720,"src":2721},"Result of running the extension","\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002F63f92d9c-f86d-45bb-9069-514c6128c113-3f94006919.png",[10,2723,2724],{},"As always, you can play around with the prompts and get better consistent output from the OpenAI API.",[166,2726,2728],{"id":2727},"adding-extension-settings","Adding Extension Settings",[10,2730,2731,2732,2734,2735,2737,2738,2741,2742,2744],{},"You may have noticed that we've added the OpenAI API key directly in the code. We should move it to VS Code settings under our extension name. To do that we need to change the ",[70,2733,142],{}," key in the ",[70,2736,112],{}," file. While we're doing that we can also move the ",[70,2739,2740],{},"maxTokens"," property instead of hardcoding it to ",[70,2743,2330],{}," in the code.",[187,2746,2748],{"className":189,"code":2747,"language":191,"meta":192,"style":192},"\u002F\u002F ..\n\"contributes\": {\n  \"configuration\": {\n    \"title\": \"My Shiny Extension\",\n    \"properties\": {\n      \"myShinyExtension.openAiApiKey\": {\n        \"type\": \"string\",\n        \"default\": \"\",\n        \"description\": \"Enter you OpenAI API Key here\"\n      },\n      \"myShinyExtension.maxTokens\": {\n        \"type\": \"number\",\n        \"default\": 1200,\n        \"description\": \"Enter the maximum number of tokens to use for each OpenAI API call\"\n      }\n    }\n  }\n},\n\u002F\u002F ..\n",[70,2749,2750,2755,2762,2769,2781,2788,2795,2807,2819,2829,2834,2841,2852,2863,2872,2877,2881,2885,2890],{"__ignoreMap":192},[196,2751,2752],{"class":198,"line":199},[196,2753,2754],{"class":202},"\u002F\u002F ..\n",[196,2756,2757,2759],{"class":198,"line":206},[196,2758,255],{"class":209},[196,2760,2761],{"class":213},": {\n",[196,2763,2764,2767],{"class":198,"line":217},[196,2765,2766],{"class":595},"  \"configuration\"",[196,2768,2761],{"class":213},[196,2770,2771,2774,2776,2779],{"class":198,"line":226},[196,2772,2773],{"class":595},"    \"title\"",[196,2775,244],{"class":213},[196,2777,2778],{"class":209},"\"My Shiny Extension\"",[196,2780,223],{"class":213},[196,2782,2783,2786],{"class":198,"line":232},[196,2784,2785],{"class":595},"    \"properties\"",[196,2787,2761],{"class":213},[196,2789,2790,2793],{"class":198,"line":238},[196,2791,2792],{"class":595},"      \"myShinyExtension.openAiApiKey\"",[196,2794,2761],{"class":213},[196,2796,2797,2800,2802,2805],{"class":198,"line":252},[196,2798,2799],{"class":595},"        \"type\"",[196,2801,244],{"class":213},[196,2803,2804],{"class":209},"\"string\"",[196,2806,223],{"class":213},[196,2808,2809,2812,2814,2817],{"class":198,"line":261},[196,2810,2811],{"class":595},"        \"default\"",[196,2813,244],{"class":213},[196,2815,2816],{"class":209},"\"\"",[196,2818,223],{"class":213},[196,2820,2821,2824,2826],{"class":198,"line":510},[196,2822,2823],{"class":595},"        \"description\"",[196,2825,244],{"class":213},[196,2827,2828],{"class":209},"\"Enter you OpenAI API Key here\"\n",[196,2830,2831],{"class":198,"line":527},[196,2832,2833],{"class":213},"      },\n",[196,2835,2836,2839],{"class":198,"line":546},[196,2837,2838],{"class":595},"      \"myShinyExtension.maxTokens\"",[196,2840,2761],{"class":213},[196,2842,2843,2845,2847,2850],{"class":198,"line":552},[196,2844,2799],{"class":595},[196,2846,244],{"class":213},[196,2848,2849],{"class":209},"\"number\"",[196,2851,223],{"class":213},[196,2853,2854,2856,2858,2861],{"class":198,"line":558},[196,2855,2811],{"class":595},[196,2857,244],{"class":213},[196,2859,2860],{"class":595},"1200",[196,2862,223],{"class":213},[196,2864,2865,2867,2869],{"class":198,"line":565},[196,2866,2823],{"class":595},[196,2868,244],{"class":213},[196,2870,2871],{"class":209},"\"Enter the maximum number of tokens to use for each OpenAI API call\"\n",[196,2873,2874],{"class":198,"line":589},[196,2875,2876],{"class":213},"      }\n",[196,2878,2879],{"class":198,"line":610},[196,2880,671],{"class":213},[196,2882,2883],{"class":198,"line":627},[196,2884,549],{"class":213},[196,2886,2887],{"class":198,"line":638},[196,2888,2889],{"class":213},"},\n",[196,2891,2892],{"class":198,"line":644},[196,2893,2754],{"class":202},[10,2895,2896,2897,2900],{},"Now these two entries will appear under \"",[70,2898,2899],{},"My Shiny Extension","\" in the VS Code settings. To read the values of these entries we can use the below code (put it just above the OpenAI service creation).",[187,2902,2904],{"className":289,"code":2903,"language":291,"meta":192,"style":192},"const configs = vscode.workspace.getConfiguration('myShinyExtension');\nconst openAIApiKey = configs.get\u003Cstring>('openAiApiKey');\nconst maxTokens = configs.get\u003Cnumber>('maxTokens');\nif (!openAIApiKey) {\n  vscode.window.showErrorMessage(\n    'Missing OpenAI API Key. Please add your key in VSCode settings to use this extension.'\n  );\n\n  return;\n}\n",[70,2905,2906,2928,2956,2981,2994,3004,3009,3013,3017,3024],{"__ignoreMap":192},[196,2907,2908,2910,2913,2915,2918,2921,2923,2926],{"class":198,"line":199},[196,2909,1013],{"class":313},[196,2911,2912],{"class":595}," configs",[196,2914,599],{"class":313},[196,2916,2917],{"class":213}," vscode.workspace.",[196,2919,2920],{"class":320},"getConfiguration",[196,2922,324],{"class":213},[196,2924,2925],{"class":209},"'myShinyExtension'",[196,2927,524],{"class":213},[196,2929,2930,2932,2935,2937,2940,2943,2945,2948,2951,2954],{"class":198,"line":206},[196,2931,1013],{"class":313},[196,2933,2934],{"class":595}," openAIApiKey",[196,2936,599],{"class":313},[196,2938,2939],{"class":213}," configs.",[196,2941,2942],{"class":320},"get",[196,2944,784],{"class":213},[196,2946,2947],{"class":595},"string",[196,2949,2950],{"class":213},">(",[196,2952,2953],{"class":209},"'openAiApiKey'",[196,2955,524],{"class":213},[196,2957,2958,2960,2963,2965,2967,2969,2971,2974,2976,2979],{"class":198,"line":217},[196,2959,1013],{"class":313},[196,2961,2962],{"class":595}," maxTokens",[196,2964,599],{"class":313},[196,2966,2939],{"class":213},[196,2968,2942],{"class":320},[196,2970,784],{"class":213},[196,2972,2973],{"class":595},"number",[196,2975,2950],{"class":213},[196,2977,2978],{"class":209},"'maxTokens'",[196,2980,524],{"class":213},[196,2982,2983,2986,2988,2991],{"class":198,"line":226},[196,2984,2985],{"class":313},"if",[196,2987,1010],{"class":213},[196,2989,2990],{"class":313},"!",[196,2992,2993],{"class":213},"openAIApiKey) {\n",[196,2995,2996,2999,3002],{"class":198,"line":232},[196,2997,2998],{"class":213},"  vscode.window.",[196,3000,3001],{"class":320},"showErrorMessage",[196,3003,398],{"class":213},[196,3005,3006],{"class":198,"line":238},[196,3007,3008],{"class":209},"    'Missing OpenAI API Key. Please add your key in VSCode settings to use this extension.'\n",[196,3010,3011],{"class":198,"line":252},[196,3012,677],{"class":213},[196,3014,3015],{"class":198,"line":261},[196,3016,562],{"emptyLinePlaceholder":561},[196,3018,3019,3022],{"class":198,"line":510},[196,3020,3021],{"class":313},"  return",[196,3023,818],{"class":213},[196,3025,3026],{"class":198,"line":527},[196,3027,555],{"class":213},[10,3029,3030],{},"Do remember that we're creating the OpenAI service instance on each API call. This is not optimal and you should move it to the constructor and handle the error scenarios appropriately.",[19,3032,3034],{"id":3033},"conclusion","Conclusion",[10,3036,3037],{},"As is evident from the article, developing a VS Code extension can be easy and fun. If you're observant you can recreate an existing thing (Hashnode AI editor in this case) in your way someplace else, and learn a ton along the way.",[10,3039,3040,3041,3043,3044,3049,3050],{},"To publish an extension we need to complete a few more steps and optionally bundle it using ",[70,3042,95],{}," or a suitable bundler. To learn more about the process you can visit these links: 1. ",[47,3045,3048],{"href":3046,"rel":3047},"https:\u002F\u002Fcode.visualstudio.com\u002Fapi\u002Fworking-with-extensions\u002Fpublishing-extension",[51],"publishing an extension",", 2. ",[47,3051,3054],{"href":3052,"rel":3053},"https:\u002F\u002Fcode.visualstudio.com\u002Fapi\u002Fworking-with-extensions\u002Fbundling-extension",[51],"Bundling an extension",[10,3056,3057,3058,337],{},"This was just a sneak peek of the extension I created. If interested, you can look at the complete source code of the extension ",[47,3059,3062],{"href":3060,"rel":3061},"https:\u002F\u002Fgithub.com\u002Fra-jeev\u002Fwrite-assist-ai",[51],"here",[10,3064,3065,3066,337],{},"If you want to try out the extension (Write Assist AI), you can get it from ",[47,3067,3062],{"href":3068,"rel":3069},"https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=ra-jeev.write-assist-ai",[51],[10,3071,3072],{},"I hope you liked reading the article. If you found any mistakes in the article, please let me know in the comments. Your suggestions and feedback are most welcome.",[10,3074,3075],{},[3076,3077,3078],"em",{},"-- Keep adding the bits, soon you'll have more bytes than you may need. :-)",[3080,3081,3082],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":192,"searchDepth":206,"depth":206,"links":3084},[3085,3086,3087,3094],{"id":21,"depth":206,"text":22},{"id":41,"depth":206,"text":42},{"id":105,"depth":206,"text":106,"children":3088},[3089,3090,3091,3092,3093],{"id":168,"depth":217,"text":169},{"id":275,"depth":217,"text":276},{"id":1147,"depth":217,"text":1148},{"id":1618,"depth":217,"text":1619},{"id":2727,"depth":217,"text":2728},{"id":3033,"depth":206,"text":3034},null,"\u002Fimages\u002Fposts\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension\u002Fb2749874-26ba-49da-9a07-ef174c979231-e1d533e1e6.png","2023-06-19T20:19:25.949Z","Rabbit holes are many, and as a developer, you keep falling into one or the other during your journey. This is not necessarily a bad thing—granted that it may frustrate you—that...",false,"md","clj3avb7h000j09l4fc3j2uk8",{},"\u002Fcreating-an-openai-powered-writing-assistant-vs-code-extension",{"title":5,"description":3098},"creating-an-openai-powered-writing-assistant-vs-code-extension",[3107,291,3108,3109,3110],"javascript","openai","vscode-extensions","chatgpt","tDl_ZrhwbMF6HwBebBTmWgxFqwGwKz3ifZti8dufBOM",1780470200096]