Skip to content

Commit 8b5d4a4

Browse files
author
Jefferson Pires
committed
Added project files
1 parent d62c249 commit 8b5d4a4

30 files changed

+1473
-0
lines changed

ChatGPT.cs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using OpenAI_API;
2+
using OpenAI_API.Completions;
3+
using OpenAI_API.Models;
4+
5+
namespace JeffPires.VisualChatGPTStudio
6+
{
7+
/// <summary>
8+
/// Static class containing methods for interacting with the ChatGPT API.
9+
/// </summary>
10+
static class ChatGPT
11+
{
12+
/// <summary>
13+
/// Requests a completion from the OpenAI API using the given options.
14+
/// </summary>
15+
/// <param name="options">The options to use for the request.</param>
16+
/// <param name="request">The request to send to the API.</param>
17+
/// <param name="resultHandler">The action to take when the result is received.</param>
18+
/// <returns>A task representing the completion request.</returns>
19+
public static async Task Request(OptionPageGrid options, string request, Action<int, CompletionResult> resultHandler)
20+
{
21+
OpenAIAPI api = new(options.ApiKey);
22+
23+
Model model = Model.DavinciText;
24+
25+
switch (options.Model)
26+
{
27+
case ModelLanguageEnum.TextCurie001:
28+
model = Model.CurieText;
29+
break;
30+
case ModelLanguageEnum.TextBabbage001:
31+
model = Model.BabbageText;
32+
break;
33+
case ModelLanguageEnum.TextAda001:
34+
model = Model.AdaText;
35+
break;
36+
case ModelLanguageEnum.CodeDavinci:
37+
model = Model.DavinciCode;
38+
break;
39+
case ModelLanguageEnum.CodeCushman:
40+
model = Model.CushmanCode;
41+
break;
42+
}
43+
44+
CompletionRequest completionRequest = new(request, model, options.MaxTokens, options.Temperature, presencePenalty: options.PresencePenalty, frequencyPenalty: options.FrequencyPenalty, top_p: options.TopP);
45+
46+
await api.Completions.StreamCompletionAsync(completionRequest, resultHandler);
47+
}
48+
}
49+
}

Commands/Commands/AddComments.cs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using EnvDTE;
2+
using JeffPires.VisualChatGPTStudio.Commands.Commands;
3+
4+
namespace JeffPires.VisualChatGPTStudio
5+
{
6+
[Command(PackageIds.AddComments)]
7+
internal sealed class AddComments : BaseChatGPTCommand<AddComments>
8+
{
9+
protected override CommandType GetCommandType(string selectedText)
10+
{
11+
if (selectedText.Contains(Environment.NewLine))
12+
{
13+
return CommandType.Erase;
14+
}
15+
16+
return CommandType.InsertBefore;
17+
}
18+
19+
protected override string GetCommand(string selectedText)
20+
{
21+
if (selectedText.Contains(Environment.NewLine))
22+
{
23+
return $"Rewrite the code with comments{Environment.NewLine}{Environment.NewLine}{TextFormat.FormatSelection(selectedText)}";
24+
}
25+
26+
return $"Comment{Environment.NewLine}{Environment.NewLine}{TextFormat.FormatSelection(selectedText)}";
27+
}
28+
}
29+
}

Commands/Commands/AddSummary.cs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using EnvDTE;
2+
using JeffPires.VisualChatGPTStudio.Commands.Commands;
3+
4+
namespace JeffPires.VisualChatGPTStudio
5+
{
6+
[Command(PackageIds.AddSummary)]
7+
internal sealed class AddSummary : BaseChatGPTCommand<AddSummary>
8+
{
9+
protected override CommandType GetCommandType(string selectedText)
10+
{
11+
return CommandType.InsertBefore;
12+
}
13+
14+
protected override string GetCommand(string selectedText)
15+
{
16+
return TextFormat.FormatCommandForSummary("Only write a comment as C# summary format like\r\n\r\n{0}\r\n\r\nfor this", selectedText);
17+
}
18+
}
19+
}

Commands/Commands/AddTests.cs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using EnvDTE;
2+
using JeffPires.VisualChatGPTStudio.Commands.Commands;
3+
4+
namespace JeffPires.VisualChatGPTStudio
5+
{
6+
[Command(PackageIds.AddTests)]
7+
internal sealed class AddTests : BaseChatGPTCommand<AddTests>
8+
{
9+
protected override CommandType GetCommandType(string selectedText)
10+
{
11+
return CommandType.InsertAfter;
12+
}
13+
14+
protected override string GetCommand(string selectedText)
15+
{
16+
return $"Create unit tests{Environment.NewLine}{Environment.NewLine}{TextFormat.FormatSelection(selectedText)}";
17+
}
18+
}
19+
}

Commands/Commands/AskAnything.cs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using EnvDTE;
2+
using JeffPires.VisualChatGPTStudio.Commands.Commands;
3+
4+
namespace JeffPires.VisualChatGPTStudio
5+
{
6+
[Command(PackageIds.AskAnything)]
7+
internal sealed class AskAnything : BaseChatGPTCommand<AskAnything>
8+
{
9+
protected override CommandType GetCommandType(string selectedText)
10+
{
11+
return CommandType.InsertAfter;
12+
}
13+
14+
protected override string GetCommand(string selectedText)
15+
{
16+
return TextFormat.FormatSelection(selectedText);
17+
}
18+
}
19+
}
+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
using EnvDTE;
2+
using OpenAI_API.Completions;
3+
using System.Linq;
4+
using Span = Microsoft.VisualStudio.Text.Span;
5+
6+
namespace JeffPires.VisualChatGPTStudio.Commands.Commands
7+
{
8+
/// <summary>
9+
/// Base abstract class for commands
10+
/// </summary>
11+
/// <typeparam name="TCommand">The type of the command.</typeparam>
12+
/// <seealso cref="BaseCommand&lt;&gt;" />
13+
internal abstract class BaseChatGPTCommand<TCommand> : BaseCommand<TCommand> where TCommand : class, new()
14+
{
15+
const string EXTENSION_NAME = "Visual chatGPT Studio";
16+
17+
protected DocumentView docView;
18+
private string selectedText;
19+
private int position;
20+
private int positionStart;
21+
private int positionEnd;
22+
private int lineLength;
23+
private bool firstInteration;
24+
25+
/// <summary>
26+
/// Gets the options.
27+
/// </summary>
28+
public OptionPageGrid Options
29+
{
30+
get
31+
{
32+
return ((VisuallChatGPTStudioPackage)this.Package).Options;
33+
}
34+
}
35+
36+
/// <summary>
37+
/// Gets the type of command.
38+
/// </summary>
39+
/// <param name="selectedText">The selected text.</param>
40+
/// <returns>The type of command.</returns>
41+
protected abstract CommandType GetCommandType(string selectedText);
42+
43+
/// <summary>
44+
/// Gets the command for the given selected text.
45+
/// </summary>
46+
/// <param name="selectedText">The selected text.</param>
47+
/// <returns>The command.</returns>
48+
protected abstract string GetCommand(string selectedText);
49+
50+
/// <summary>
51+
/// Executes asynchronously when the command is invoked and <see cref="M:Community.VisualStudio.Toolkit.BaseCommand.Execute(System.Object,System.EventArgs)" /> isn't overridden.
52+
/// </summary>
53+
/// <param name="e"></param>
54+
/// <remarks>
55+
/// Use this method instead of <see cref="M:Community.VisualStudio.Toolkit.BaseCommand.Execute(System.Object,System.EventArgs)" /> if you're invoking any async tasks by using async/await patterns.
56+
/// </remarks>
57+
protected override async Task ExecuteAsync(OleMenuCmdEventArgs e)
58+
{
59+
try
60+
{
61+
if (string.IsNullOrWhiteSpace(Options.ApiKey))
62+
{
63+
await VS.MessageBox.ShowAsync(EXTENSION_NAME, "Please, set the OpenAI API key.", buttons: Microsoft.VisualStudio.Shell.Interop.OLEMSGBUTTON.OLEMSGBUTTON_OK);
64+
65+
Package.ShowOptionPage(typeof(OptionPageGrid));
66+
67+
return;
68+
}
69+
70+
firstInteration = true;
71+
lineLength = 0;
72+
73+
await Package.JoinableTaskFactory.SwitchToMainThreadAsync();
74+
75+
docView = await VS.Documents.GetActiveDocumentViewAsync();
76+
77+
if (docView?.TextView == null) return;
78+
79+
position = docView.TextView.Caret.Position.BufferPosition.Position;
80+
positionStart = docView.TextView.Selection.Start.Position.Position;
81+
positionEnd = docView.TextView.Selection.End.Position.Position;
82+
83+
selectedText = docView.TextView.Selection.StreamSelectionSpan.GetText();
84+
85+
if (string.IsNullOrWhiteSpace(selectedText))
86+
{
87+
await VS.MessageBox.ShowAsync(EXTENSION_NAME, "Please select the code.", buttons: Microsoft.VisualStudio.Shell.Interop.OLEMSGBUTTON.OLEMSGBUTTON_OK);
88+
89+
return;
90+
}
91+
92+
if (CheckIfSelectedTwoOrMoreMethods(selectedText))
93+
{
94+
await VS.MessageBox.ShowAsync(EXTENSION_NAME, "Please select one method at a time.", buttons: Microsoft.VisualStudio.Shell.Interop.OLEMSGBUTTON.OLEMSGBUTTON_OK);
95+
96+
return;
97+
}
98+
99+
await VS.StatusBar.ShowProgressAsync("Waiting chatGPT response", 1, 2);
100+
101+
await Request(selectedText);
102+
}
103+
catch (Exception ex)
104+
{
105+
await VS.StatusBar.ShowProgressAsync(ex.Message, 2, 2);
106+
107+
await VS.MessageBox.ShowAsync(EXTENSION_NAME, ex.Message, Microsoft.VisualStudio.Shell.Interop.OLEMSGICON.OLEMSGICON_WARNING, Microsoft.VisualStudio.Shell.Interop.OLEMSGBUTTON.OLEMSGBUTTON_OK);
108+
}
109+
}
110+
111+
/// <summary>
112+
/// Requests the specified selected text from ChatGPT
113+
/// </summary>
114+
/// <param name="selectedText">The selected text.</param>
115+
private async Task Request(string selectedText)
116+
{
117+
await ChatGPT.Request(Options, GetCommand(selectedText), ResultHandler);
118+
119+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
120+
121+
try
122+
{
123+
//Some documents don't has format
124+
(await VS.GetServiceAsync<DTE, DTE>()).ExecuteCommand("Edit.FormatDocument", string.Empty);
125+
}
126+
catch (Exception)
127+
{
128+
129+
}
130+
}
131+
132+
/// <summary>
133+
/// Results handler.
134+
/// </summary>
135+
/// <param name="index">The index.</param>
136+
/// <param name="result">The result.</param>
137+
private async void ResultHandler(int index, CompletionResult result)
138+
{
139+
if (firstInteration)
140+
{
141+
await VS.StatusBar.ShowProgressAsync("Receiving chatGPT response", 2, 2);
142+
143+
CommandType commandType = GetCommandType(selectedText);
144+
145+
if (commandType == CommandType.Erase)
146+
{
147+
position = positionStart;
148+
149+
//Erase current code
150+
_ = (docView.TextBuffer?.Replace(new Span(position, docView.TextView.Selection.StreamSelectionSpan.GetText().Length), String.Empty));
151+
}
152+
else if (commandType == CommandType.InsertBefore)
153+
{
154+
position = positionStart;
155+
156+
_ = (docView.TextBuffer?.Insert(position, Environment.NewLine));
157+
}
158+
else
159+
{
160+
position = positionEnd;
161+
162+
_ = (docView.TextBuffer?.Insert(position, Environment.NewLine));
163+
}
164+
165+
firstInteration = false;
166+
}
167+
168+
string resultText = result.ToString();
169+
170+
docView.TextBuffer?.Insert(position, resultText);
171+
172+
position += resultText.Length;
173+
174+
lineLength += resultText.Length;
175+
176+
if (lineLength > 160 && typeof(TCommand) == typeof(AskAnything))
177+
{
178+
lineLength = 0;
179+
MovetoNextLine();
180+
}
181+
}
182+
183+
/// <summary>
184+
/// Move to the next line.
185+
/// </summary>
186+
private void MovetoNextLine()
187+
{
188+
position = docView.TextView.Caret.Position.BufferPosition.GetContainingLine().End.Position;
189+
190+
docView.TextView.Caret.MoveTo(docView.TextView.Caret.Position.BufferPosition.GetContainingLine().End);
191+
192+
_ = (docView.TextBuffer?.Insert(position, Environment.NewLine));
193+
}
194+
195+
/// <summary>
196+
/// Check If Selected Two Or More Methods
197+
/// </summary>
198+
/// <param name="text">The text to check</param>
199+
/// <returns>True if has Selected Two Or More Methods</returns>
200+
private bool CheckIfSelectedTwoOrMoreMethods(string text)
201+
{
202+
string[] words = text.Split(' ');
203+
204+
return words.Count(w => w == "public" || w == "private" || w == "protected") >= 2;
205+
}
206+
}
207+
208+
/// <summary>
209+
/// Enum to represent the different types of commands that can be used.
210+
/// </summary>
211+
enum CommandType
212+
{
213+
Erase,
214+
InsertBefore,
215+
InsertAfter
216+
}
217+
}

Commands/Commands/Complete.cs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using EnvDTE;
2+
3+
namespace JeffPires.VisualChatGPTStudio.Commands.Commands
4+
{
5+
[Command(PackageIds.Complete)]
6+
internal sealed class Complete : BaseChatGPTCommand<Complete>
7+
{
8+
protected override CommandType GetCommandType(string selectedText)
9+
{
10+
return CommandType.InsertAfter;
11+
}
12+
13+
protected override string GetCommand(string selectedText)
14+
{
15+
return TextFormat.FormatForCompleteCommand("Please complete", selectedText, docView.FilePath);
16+
}
17+
}
18+
}

Commands/Commands/Explain.cs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using EnvDTE;
2+
using JeffPires.VisualChatGPTStudio.Commands.Commands;
3+
4+
namespace JeffPires.VisualChatGPTStudio
5+
{
6+
[Command(PackageIds.Explain)]
7+
internal sealed class Explain : BaseChatGPTCommand<Explain>
8+
{
9+
protected override CommandType GetCommandType(string selectedText)
10+
{
11+
return CommandType.InsertBefore;
12+
}
13+
14+
protected override string GetCommand(string selectedText)
15+
{
16+
return $"Explain{Environment.NewLine}{Environment.NewLine}{TextFormat.FormatSelection(selectedText)}";
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)