Skip to content

Commit

Permalink
refact_vs_classic update (#10)
Browse files Browse the repository at this point in the history
* adding files for refact extension

* testing github workflow

* removing default exe to test workflow

* uploading artifacts in workflow

* readding exe

* cleaning up files

* C/C++ now works with grey text

* fixed minor typo

* can now select intellisense options, whitespace causes less problems for grey text completions and the code will only ask for completions when the cursor is at the end of a line

* removing binary and updating build scripts

* fixing build script typo

* fixing minor build naming issue

* Updating code to be consistent with new build script

* improved the options page

* added comments and fixed formatting

* updating enter behaviour

* fixing minor bugs and functional issues

* added code to fix issues around single vs multiline completions issues #9 and #6

* added scroll bars for the options page

* adding status bar and killing server process on shutdown

* fixing minor bug where grey text was inserted into incorrect places
  • Loading branch information
digital-phoenix authored Dec 26, 2023
1 parent a1a5ca2 commit 77c624c
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 10 deletions.
2 changes: 1 addition & 1 deletion MultilineGreyText/InlineTaggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace RefactAI
internal class InlineTaggerProvider : IViewTaggerProvider
{
//create a single tagger for each buffer.
//the MultilineGreyTextTagger displays the grey text in the editor.
//the InlineGreyTextTagger displays grey text inserted between user text in the editor.
public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag
{
Func<ITagger<T>> sc = delegate () { return new InlineGreyTextTagger((IWpfTextView)textView) as ITagger<T>; };
Expand Down
4 changes: 0 additions & 4 deletions MultilineGreyText/MultilineGreyTextTagger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,6 @@ public void SetSuggestion(String newSuggestion, bool inline, int caretPoint){
String line = untrim.TrimStart();
int offset = untrim.Length - line.Length;

/* if (caretPoint > untrim.Length){
newSuggestion = (new string(' ', caretPoint - untrim.Length)) + newSuggestion;
}*/
caretPoint = Math.Max(0, caretPoint - offset);

String combineSuggestion = line + newSuggestion;
Expand Down
2 changes: 1 addition & 1 deletion MultilineGreyText/RefactCompletionCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public void GetLSPCompletions(){

String pattern ="[\\s\\t\\n\\r" + escapedSymbols + "]*";
Match m = Regex.Match(afterCaret, pattern, RegexOptions.IgnoreCase);
if(!m.Success)
if(!(m.Success && m.Index == 0 && m.Length == afterCaret.Length))
return;
}

Expand Down
6 changes: 6 additions & 0 deletions MultilineGreyText/RefactExtension.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@
<Compile Include="RefactCompletionCommandHandler.cs" />
<Compile Include="RefactCompletionHandlerProvider.cs" />
<Compile Include="RefactLanguageClient.cs" />
<Compile Include="StatusBar.cs" />
<Compile Include="VisualTreeUtils.cs" />
<Compile Include="TestTag.cs" />
<Compile Include="RefactPackage.cs" />
</ItemGroup>
Expand Down Expand Up @@ -145,6 +147,9 @@
<VSCTCompile Include="RefactPackage.vsct">
<ResourceName>Menus.ctmenu</ResourceName>
</VSCTCompile>
<Content Include="Resources\debug-disconnect.png">
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<Content Include="Resources\refact-lsp.exe">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
Expand All @@ -161,6 +166,7 @@
<EmbeddedResource Include="VSPackage.resx">
<MergeWithCTO>true</MergeWithCTO>
<ManifestResourceName>VSPackage</ManifestResourceName>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
Expand Down
51 changes: 49 additions & 2 deletions MultilineGreyText/RefactLanguageClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
using Newtonsoft.Json.Linq;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.Shell.Interop;
using static System.Net.Mime.MediaTypeNames;
using System.Windows.Forms;
using System.Windows.Media;
using Microsoft.VisualStudio;
using Community.VisualStudio.Toolkit;
using System.Windows.Controls;
using System.Windows;

namespace RefactAI{

Expand All @@ -23,8 +31,14 @@ namespace RefactAI{
[Export(typeof(ILanguageClient))]
[RunOnContext(RunningContext.RunOnHost)]

public class RefactLanguageClient : ILanguageClient, ILanguageClientCustomMessage2{
public class RefactLanguageClient : ILanguageClient, ILanguageClientCustomMessage2, IDisposable{
//service provider is used to get the IVsServiceProvider which is needed for the status bar
[Import]
internal SVsServiceProvider ServiceProvider { get; set; }

private Connection c;
private Process serverProcess = null;
private StatusBar statusBar;

//lsp instance
internal static RefactLanguageClient Instance{
Expand Down Expand Up @@ -72,6 +86,7 @@ internal JsonRpc Rpc{
public RefactLanguageClient(){
Instance = this;
files = new HashSet<string>();
statusBar = new StatusBar();
}

//gets/sets lsp configuration sections
Expand Down Expand Up @@ -110,6 +125,7 @@ public async void AddFile(String filePath, String text){
await Rpc.NotifyWithParameterObjectAsync("textDocument/didChange", openParam);
}catch (Exception e){
Debug.Write("InvokeTextDocumentDidChangeAsync Server Exception " + e.ToString());
ShowStatusBarError("Server Exception: \n" + e.Message);
}
}

Expand Down Expand Up @@ -168,6 +184,7 @@ public async Task OnLoadedAsync(){
if (StartAsync != null){
loaded = true;
await StartAsync.InvokeAsync(this, EventArgs.Empty);
statusBar = new StatusBar();
}
}

Expand Down Expand Up @@ -199,6 +216,8 @@ public Task<InitializationFailureContext> OnServerInitializeFailedAsync(ILanguag
FailureMessage = message,
};

ShowStatusBarError(message);

return Task.FromResult(failureContext);
}

Expand All @@ -217,6 +236,7 @@ public async void InvokeTextDocumentDidChangeAsync(Uri fileURI, int version, Tex
await Rpc.NotifyWithParameterObjectAsync("textDocument/didChange", changesParam);
}catch(Exception e){
Debug.Write("InvokeTextDocumentDidChangeAsync Server Exception " + e.ToString());
ShowStatusBarError("Server Exception: \n" + e.Message);
}
}
}
Expand All @@ -240,7 +260,8 @@ public async Task<string> RefactCompletion(PropertyCollection props, String file
textDocument = new { uri = fileUri },
position = new{ line = lineN, character = character }
};

ShowLoadingStatusBar();

var res = await this.Rpc.InvokeWithParameterObjectAsync<JToken>("refact/getCompletions", argObj2);

//process results
Expand All @@ -249,13 +270,39 @@ public async Task<string> RefactCompletion(PropertyCollection props, String file
suggestions.Add(s["code_completion"].ToString());
}

ShowDefaultStatusBar();

return suggestions[0];
}catch (Exception e){
Debug.Write("Error " + e.ToString());
ShowStatusBarError("Error: \n" + e.Message);
return null;
}
}

async void ShowDefaultStatusBar(){
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
statusBar.ShowDefaultStatusBar();
}

async void ShowStatusBarError(String error){
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
statusBar.ShowStatusBarError(error);
}

async void ShowLoadingStatusBar(){
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
statusBar.ShowLoadingSymbol();
}

public void Dispose(){
if(serverProcess != null){
serverProcess.Kill();
serverProcess.WaitForExit();
serverProcess.Dispose();
}
}

//ilanguage client middle layer
internal class RefactMiddleLayer : ILanguageClientMiddleLayer{
internal readonly static RefactMiddleLayer Instance = new RefactMiddleLayer();
Expand Down
3 changes: 1 addition & 2 deletions MultilineGreyText/RefactPackage.vsct
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@
</Group>
</Groups>

<!--Buttons section. -->
<!--This section defines the elements the user can interact with, like a menu command or a button
<!--Buttons section. -es the elements the user can interact with, like a menu command or a button
or combo box in a toolbar. -->
<Buttons>
<!--To define a menu group you have to specify its ID, the parent menu and its display priority.
Expand Down
Binary file added MultilineGreyText/Resources/debug-disconnect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions MultilineGreyText/StatusBar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using Microsoft.VisualStudio.Imaging;
using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace RefactAI
{
internal class StatusBar{
Panel panel;
StackPanel stack;
Brush whiteBrush;
Brush errorBrush;
Brush transparentBrush;

public StatusBar(){
stack = new StackPanel();
stack.Width = 75.0;
stack.Orientation = Orientation.Horizontal;
panel = VisualTreeUtils.FindChild(Application.Current.MainWindow, childName: "StatusBarPanel") as Panel;
whiteBrush = new SolidColorBrush(Colors.White);
errorBrush = new SolidColorBrush(Colors.Red);
transparentBrush = new SolidColorBrush(Colors.Transparent);
panel.Children.Add(stack);
ShowDefaultStatusBar();
}

public void ShowDefaultStatusBar(){
stack.Children.Clear();
stack.Background = transparentBrush;
stack.Children.Add(CreateText("|{ Refact"));
}

public void ShowStatusBarError(string error){
stack.Children.Clear();
stack.Background = errorBrush;
stack.Children.Add(CreateImage("debug-disconnect.png"));
stack.Children.Add(CreateText("Refact.ai"));
stack.ToolTip = createToolTip(text: error, stack);
}

public void ShowLoadingSymbol(){
stack.Children.Clear();
stack.Background = transparentBrush;
var img = new CrispImage() { Moniker = KnownMonikers.Sync, VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center, Width = 16, Height = 16 };
stack.Children.Add(img);
stack.Children.Add(CreateText("Refact.ai"));
}

ToolTip createToolTip(String text, UIElement parent){
ToolTip toolTip = new ToolTip();
toolTip.Content = text;
toolTip.IsEnabled = true;
toolTip.PlacementTarget = parent;
toolTip.Placement = System.Windows.Controls.Primitives.PlacementMode.Top;
return toolTip;
}

public TextBlock CreateText(string text){
TextBlock textBlock = new TextBlock();
textBlock.Inlines.Add(text);
textBlock.FontSize = 12.0;
textBlock.Foreground = whiteBrush;
textBlock.VerticalAlignment = VerticalAlignment.Center;
return textBlock;
}

Image CreateImage(string filename){
Image myImage = new Image();
myImage.Height = 16;

BitmapImage myBitmapImage = new BitmapImage();

myBitmapImage.BeginInit();
var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Resources", filename);

myBitmapImage.UriSource = new Uri(path);
myBitmapImage.DecodePixelWidth = 200;
myBitmapImage.EndInit();
myImage.Source = myBitmapImage;
return myImage;
}

}
}
39 changes: 39 additions & 0 deletions MultilineGreyText/VisualTreeUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//This file is thanks to madskristensen https://github.com/madskristensen/ShowTheShortcut/blob/master/src/StatusbarInjector.cs

using System.Windows.Media;
using System.Windows;

namespace RefactAI
{
internal static class VisualTreeUtils{
//breadth first search of visual tree for DependencyObject with name childName
public static DependencyObject FindChild(DependencyObject parent, string childName){
if (parent == null){
return null;
}

int childrenCount = VisualTreeHelper.GetChildrenCount(parent);

for (int i = 0; i < childrenCount; i++){
DependencyObject child = VisualTreeHelper.GetChild(parent, i);

if (child is FrameworkElement frameworkElement && frameworkElement.Name == childName)
{
return frameworkElement;
}
}

for (int i = 0; i < childrenCount; i++){
DependencyObject child = VisualTreeHelper.GetChild(parent, i);

child = FindChild(child, childName);

if (child != null){
return child;
}
}

return null;
}
}
}

0 comments on commit 77c624c

Please sign in to comment.