diff --git a/CodeiumVS/CodeiumVS.csproj b/CodeiumVS/CodeiumVS.csproj index 240342c..1e453cb 100644 --- a/CodeiumVS/CodeiumVS.csproj +++ b/CodeiumVS/CodeiumVS.csproj @@ -208,4 +208,4 @@ --> - \ No newline at end of file + diff --git a/CodeiumVS/LanguageServer/LanguageServer.cs b/CodeiumVS/LanguageServer/LanguageServer.cs index f2ec2f8..bd0388f 100644 --- a/CodeiumVS/LanguageServer/LanguageServer.cs +++ b/CodeiumVS/LanguageServer/LanguageServer.cs @@ -25,7 +25,7 @@ namespace CodeiumVS; public class LanguageServer { private string _languageServerURL; - private string _languageServerVersion = "1.6.22"; + private string _languageServerVersion = "1.6.38"; private int _port = 0; private Process _process; diff --git a/CodeiumVS/SettingsPage.cs b/CodeiumVS/SettingsPage.cs index ee85493..e3dff66 100644 --- a/CodeiumVS/SettingsPage.cs +++ b/CodeiumVS/SettingsPage.cs @@ -98,7 +98,8 @@ public bool EnableLanguageServerProxy [Category("Codeium")] [DisplayName("Enable Codeium Indexing")] - [Description("Allows Codeium to index your current repository and provide better chat and autocomplete responses based on relevant parts of your codebase. Requires restart.")] + [Description( + "Allows Codeium to index your current repository and provide better chat and autocomplete responses based on relevant parts of your codebase. Requires restart.")] public bool EnableIndexing { get { @@ -111,7 +112,8 @@ public bool EnableIndexing [Category("Codeium")] [DisplayName("Indexing Max Workspace Size (File Count)")] - [Description("If indexing is enabled, we will only attempt to index workspaces that have up to this many files. This file count ignores .gitignore and binary files.")] + [Description( + "If indexing is enabled, we will only attempt to index workspaces that have up to this many files. This file count ignores .gitignore and binary files.")] public int IndexingMaxWorkspaceSize { get { diff --git a/CodeiumVS/SuggestionUI/InlineGreyTextTagger.cs b/CodeiumVS/SuggestionUI/InlineGreyTextTagger.cs index c9f6452..98c2194 100644 --- a/CodeiumVS/SuggestionUI/InlineGreyTextTagger.cs +++ b/CodeiumVS/SuggestionUI/InlineGreyTextTagger.cs @@ -18,105 +18,106 @@ namespace CodeiumVS { - internal class InlineGreyTextTagger : ITagger - { - protected readonly IWpfTextView view; - protected SnapshotSpan currentSpan; - private Brush greyBrush; - private StackPanel stackPanel; - public event EventHandler TagsChanged; +internal class InlineGreyTextTagger : ITagger +{ + protected readonly IWpfTextView view; + protected SnapshotSpan currentSpan; + private Brush greyBrush; + private StackPanel stackPanel; + public event EventHandler TagsChanged; - public InlineGreyTextTagger(IWpfTextView view) - { - this.view = view; - this.greyBrush = new SolidColorBrush(Colors.Gray); - this.stackPanel = new StackPanel(); - } + public InlineGreyTextTagger(IWpfTextView view) + { + this.view = view; + this.greyBrush = new SolidColorBrush(Colors.Gray); + this.stackPanel = new StackPanel(); + } + /// The span of text that this adornment will elide. + /// Adornment corresponding to given data. May be null. + public void UpdateAdornment(UIElement text) + { + ClearAdornment(); + stackPanel.Children.Add(text); + stackPanel.UpdateLayout(); + } - /// The span of text that this adornment will elide. - /// Adornment corresponding to given data. May be null. - public void UpdateAdornment(UIElement text) - { - ClearAdornment(); - stackPanel.Children.Add(text); - stackPanel.UpdateLayout(); - } + public void ClearAdornment() + { + stackPanel.Children.Clear(); + stackPanel = new StackPanel(); + } - public void ClearAdornment() - { - stackPanel.Children.Clear(); - stackPanel = new StackPanel(); - } + public void FormatText(TextRunProperties props) + { + if (props == null) { return; } - public void FormatText(TextRunProperties props) + foreach (TextBlock block in stackPanel.Children) { - if (props == null) - { - return; - } - - foreach (TextBlock block in stackPanel.Children) - { - block.FontFamily = props.Typeface.FontFamily; - block.FontSize = props.FontRenderingEmSize; - } + block.FontFamily = props.Typeface.FontFamily; + block.FontSize = props.FontRenderingEmSize; } + } - public void MarkDirty() - { - var changeStart = view.TextViewLines.FirstVisibleLine.Start; - var changeEnd = view.TextViewLines.LastVisibleLine.Start; - - var startLine = view.TextSnapshot.GetLineFromPosition(changeStart); - var endLine = view.TextSnapshot.GetLineFromPosition(changeEnd); + public void MarkDirty() + { + var changeStart = view.TextViewLines.FirstVisibleLine.Start; + var changeEnd = view.TextViewLines.LastVisibleLine.Start; - var span = new SnapshotSpan(startLine.Start, endLine.EndIncludingLineBreak). - TranslateTo(targetSnapshot: view.TextBuffer.CurrentSnapshot, SpanTrackingMode.EdgePositive); + var startLine = view.TextSnapshot.GetLineFromPosition(changeStart); + var endLine = view.TextSnapshot.GetLineFromPosition(changeEnd); - TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(span.Start, span.End))); - } + var span = new SnapshotSpan(startLine.Start, endLine.EndIncludingLineBreak) + .TranslateTo(targetSnapshot: view.TextBuffer.CurrentSnapshot, + SpanTrackingMode.EdgePositive); - // Produces tags on the snapshot that the tag consumer asked for. - public virtual IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) - { - if (stackPanel.Children.Count == 0) - { - yield break; - } - - ITextSnapshot requestedSnapshot = spans[0].Snapshot; - double width = view.FormattedLineSource.ColumnWidth * ((stackPanel.Children[0] as TextBlock).Inlines.First() as Run).Text.Length; - double height = view.LineHeight; - - stackPanel.Measure(new Size(width, height)); - stackPanel.MaxHeight = height; - stackPanel.MinHeight = height; - stackPanel.MinWidth = width; - stackPanel.MaxWidth = width; - var caretLine = view.Caret.ContainingTextViewLine; - SnapshotPoint point = view.Caret.Position.BufferPosition.TranslateTo(requestedSnapshot, PointTrackingMode.Positive); - var line = requestedSnapshot.GetLineFromPosition(point); - var span = new SnapshotSpan(point, point); - - IntraTextAdornmentTag tag = new IntraTextAdornmentTag(stackPanel, null, PositionAffinity.Successor); - yield return new TagSpan(span, tag); - } + TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(span.Start, span.End))); + } + // Produces tags on the snapshot that the tag consumer asked for. + public virtual IEnumerable> + GetTags(NormalizedSnapshotSpanCollection spans) + { + if (stackPanel.Children.Count == 0) { yield break; } + + ITextSnapshot requestedSnapshot = spans[0].Snapshot; + double width = view.FormattedLineSource.ColumnWidth * + ((stackPanel.Children[0] as TextBlock).Inlines.First() as Run).Text.Length; + double height = view.LineHeight; + + stackPanel.Measure(new Size(width, height)); + stackPanel.MaxHeight = height; + stackPanel.MinHeight = height; + stackPanel.MinWidth = width; + stackPanel.MaxWidth = width; + var caretLine = view.Caret.ContainingTextViewLine; + SnapshotPoint point = view.Caret.Position.BufferPosition.TranslateTo( + requestedSnapshot, PointTrackingMode.Positive); + var line = requestedSnapshot.GetLineFromPosition(point); + var span = new SnapshotSpan(point, point); + + IntraTextAdornmentTag tag = + new IntraTextAdornmentTag(stackPanel, null, PositionAffinity.Successor); + yield return new TagSpan(span, tag); } +} - [Export(contractType: typeof(IViewTaggerProvider))] - [TagType(typeof(IntraTextAdornmentTag))] - [ContentType("text")] - internal class InlineTaggerProvider : IViewTaggerProvider +[Export(contractType: typeof(IViewTaggerProvider))] +[TagType(typeof(IntraTextAdornmentTag))] +[ContentType("text")] +internal class InlineTaggerProvider : IViewTaggerProvider +{ + // create a single tagger for each buffer. + // the InlineGreyTextTagger displays grey text inserted between user text in the editor. + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) + where T : ITag { - //create a single tagger for each buffer. - //the InlineGreyTextTagger displays grey text inserted between user text in the editor. - public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + Func> sc = delegate() { - Func> sc = delegate () { return new InlineGreyTextTagger((IWpfTextView)textView) as ITagger; }; - return buffer.Properties.GetOrCreateSingletonProperty(typeof(InlineGreyTextTagger), sc); - } + return new InlineGreyTextTagger((IWpfTextView)textView) as ITagger; + }; + return buffer.Properties.GetOrCreateSingletonProperty(typeof(InlineGreyTextTagger), sc); } +} } diff --git a/CodeiumVS/SuggestionUI/Mapper.cs b/CodeiumVS/SuggestionUI/Mapper.cs index 6bad736..4eee335 100644 --- a/CodeiumVS/SuggestionUI/Mapper.cs +++ b/CodeiumVS/SuggestionUI/Mapper.cs @@ -78,7 +78,7 @@ internal class KnownLanguages new LangInfo("XML", "xml", Packets.Language.LANGUAGE_XML), new LangInfo("XSL", "xsl", Packets.Language.LANGUAGE_XSL), new LangInfo("YAML", "yaml", Packets.Language.LANGUAGE_YAML), - // clang-format on + // clang-format on ]; } internal class LanguageEqualityComparer : IEqualityComparer diff --git a/CodeiumVS/SuggestionUI/StringCompare.cs b/CodeiumVS/SuggestionUI/StringCompare.cs index 66b6122..9d51b0b 100644 --- a/CodeiumVS/SuggestionUI/StringCompare.cs +++ b/CodeiumVS/SuggestionUI/StringCompare.cs @@ -6,90 +6,87 @@ namespace CodeiumVS { - public static class StringCompare - { +public static class StringCompare +{ - //returns the number of times letter c appears in s - public static int GetOccurenceOfLetter(String s, char c) - { - int n = 0; - for (int i = 0; (i = s.IndexOf(c, i)) >= 0; i++, n++) { } - return n; - } + // returns the number of times letter c appears in s + public static int GetOccurenceOfLetter(String s, char c) + { + int n = 0; + for (int i = 0; (i = s.IndexOf(c, i)) >= 0; i++, n++) {} + return n; + } - //skips whitespace - public static int nextNonWhitespace(String s, int index) - { - for (; index < s.Length && Char.IsWhiteSpace(s[index]); index++) ; ; - return index; - } + // skips whitespace + public static int nextNonWhitespace(String s, int index) + { + for (; index < s.Length && Char.IsWhiteSpace(s[index]); index++) + ; + ; + return index; + } - public static bool IsNameChar(char c) - { - return Char.IsLetterOrDigit(c) || c == '_'; - } + public static bool IsNameChar(char c) { return Char.IsLetterOrDigit(c) || c == '_'; } - //Compares the two strings to see if a is a prefix of b ignoring whitespace - public static Tuple CompareStrings(String a, String b) + // Compares the two strings to see if a is a prefix of b ignoring whitespace + public static Tuple CompareStrings(String a, String b) + { + int a_index = 0, b_index = 0; + while (a_index < a.Length && b_index < b.Length) { - int a_index = 0, b_index = 0; - while (a_index < a.Length && b_index < b.Length) + char aChar = a[a_index]; + char bChar = b[b_index]; + if (aChar == bChar) { - char aChar = a[a_index]; - char bChar = b[b_index]; - if (aChar == bChar) - { - a_index++; - b_index++; - } - else + a_index++; + b_index++; + } + else + { + if (Char.IsWhiteSpace(bChar)) { - if (Char.IsWhiteSpace(bChar)) - { - b_index = nextNonWhitespace(b, b_index); + b_index = nextNonWhitespace(b, b_index); - continue; - } - - if (Char.IsWhiteSpace(aChar) && b_index >= 1 && (!IsNameChar(b[b_index]) || !IsNameChar(b[b_index - 1]))) - { - a_index = nextNonWhitespace(a, a_index); + continue; + } - continue; - } + if (Char.IsWhiteSpace(aChar) && b_index >= 1 && + (!IsNameChar(b[b_index]) || !IsNameChar(b[b_index - 1]))) + { + a_index = nextNonWhitespace(a, a_index); - break; + continue; } - } - return new Tuple(a_index, b_index); + break; + } } - //Check if the text in the editor is a substring of the the suggestion text - //If it matches return the line number of the suggestion text that matches the current line in the editor - //else return -1 - public static int CheckSuggestion(String suggestion, String line, bool isTextInsertion = false, int insertionPoint = -1) - { - if (line.Length == 0) - { - return 0; - } + return new Tuple(a_index, b_index); + } - int index = suggestion.IndexOf(line); - int endPos = index + line.Length; - int firstLineBreak = suggestion.IndexOf('\n'); + // Check if the text in the editor is a substring of the the suggestion text + // If it matches return the line number of the suggestion text that matches the current line in + // the editor else return -1 + public static int CheckSuggestion(String suggestion, String line, bool isTextInsertion = false, + int insertionPoint = -1) + { + if (line.Length == 0) { return 0; } - if (index > -1 && (firstLineBreak == -1 || endPos < firstLineBreak)) - { - return index == 0 ? line.Length : -1; - } - else - { - Tuple res = CompareStrings(line, suggestion); - int endPoint = isTextInsertion ? line.Length - insertionPoint : line.Length; - return res.Item1 >= endPoint ? res.Item2 : -1; - } - } + int index = suggestion.IndexOf(line); + int endPos = index + line.Length; + int firstLineBreak = suggestion.IndexOf('\n'); + if (index > -1 && (firstLineBreak == -1 || endPos < firstLineBreak)) + { + return index == 0 ? line.Length : -1; + } + else + { + Tuple res = CompareStrings(line, suggestion); + int endPoint = isTextInsertion ? line.Length - insertionPoint : line.Length; + return res.Item1 >= endPoint ? res.Item2 : -1; + } } } +} diff --git a/CodeiumVS/SuggestionUI/SuggestionTag.cs b/CodeiumVS/SuggestionUI/SuggestionTag.cs index 0b395e1..499e017 100644 --- a/CodeiumVS/SuggestionUI/SuggestionTag.cs +++ b/CodeiumVS/SuggestionUI/SuggestionTag.cs @@ -4,11 +4,16 @@ namespace CodeiumVS { - //the SpaceNegotiatingAdornmentTag is used to tell the editor to create an empty space - //they work like a more complicated version of
from html - internal class SuggestionTag : SpaceNegotiatingAdornmentTag +// the SpaceNegotiatingAdornmentTag is used to tell the editor to create an empty space +// they work like a more complicated version of
from html +internal class SuggestionTag : SpaceNegotiatingAdornmentTag +{ + public SuggestionTag(double width, double topSpace, double baseline, double textHeight, + double bottomSpace, PositionAffinity affinity, object identityTag, + object providerTag) + : base(width, topSpace, baseline, textHeight, bottomSpace, affinity, identityTag, + providerTag) { - public SuggestionTag(double width, double topSpace, double baseline, double textHeight, double bottomSpace, PositionAffinity affinity, object identityTag, object providerTag) - : base(width, topSpace, baseline, textHeight, bottomSpace, affinity, identityTag, providerTag) { } } } +} diff --git a/CodeiumVS/SuggestionUI/SuggestionTagger.cs b/CodeiumVS/SuggestionUI/SuggestionTagger.cs index dae7b4e..98abefc 100644 --- a/CodeiumVS/SuggestionUI/SuggestionTagger.cs +++ b/CodeiumVS/SuggestionUI/SuggestionTagger.cs @@ -18,575 +18,526 @@ namespace CodeiumVS { - internal sealed class SuggestionTagger : ITagger - { - /// panel with multiline grey text - private StackPanel stackPanel; +internal sealed class SuggestionTagger : ITagger +{ + /// panel with multiline grey text + private StackPanel stackPanel; - /// used to set the colour of the grey text - private Brush greyBrush; + /// used to set the colour of the grey text + private Brush greyBrush; - /// used to set the colour of text that overlaps with the users text - private Brush transparentBrush; + /// used to set the colour of text that overlaps with the users text + private Brush transparentBrush; - /// contains the editor text and OnChange triggers on any text changes - ITextBuffer buffer; + /// contains the editor text and OnChange triggers on any text changes + ITextBuffer buffer; - /// current editor display, immutable data - ITextSnapshot snapshot; + /// current editor display, immutable data + ITextSnapshot snapshot; - /// the editor display object - IWpfTextView view; + /// the editor display object + IWpfTextView view; - /// contains the grey text - private IAdornmentLayer adornmentLayer; + /// contains the grey text + private IAdornmentLayer adornmentLayer; - /// true if a suggestion should be shown - private bool showSuggestion = false; - private bool isTextInsertion = false; + /// true if a suggestion should be shown + private bool showSuggestion = false; + private bool isTextInsertion = false; - /// line number the suggestion should be displayed at - private int currentTextLineN; - private int suggestionIndex; - private int insertionPoint; - private int userIndex; - private String userEndingText; - private String virtualText = ""; + /// line number the suggestion should be displayed at + private int currentTextLineN; + private int suggestionIndex; + private int insertionPoint; + private int userIndex; + private String userEndingText; + private String virtualText = ""; - /// suggestion to display - /// first string is to match against second item: array is for formatting - private static Tuple suggestion = null; + /// suggestion to display + /// first string is to match against second item: array is for formatting + private static Tuple suggestion = null; - private InlineGreyTextTagger GetTagger() - { - var key = typeof(InlineGreyTextTagger); - var props = view.TextBuffer.Properties; - if (props.ContainsProperty(key)) - { - return props.GetProperty(key); - } - else - { - return null; - } - } + private InlineGreyTextTagger GetTagger() + { + var key = typeof(InlineGreyTextTagger); + var props = view.TextBuffer.Properties; + if (props.ContainsProperty(key)) { return props.GetProperty(key); } + else { return null; } + } - public void SetSuggestion(String newSuggestion, int caretPoint) - { - newSuggestion = newSuggestion.TrimEnd(); - newSuggestion = newSuggestion.Replace("\r", ""); - ClearSuggestion(); + public void SetSuggestion(String newSuggestion, int caretPoint) + { + newSuggestion = newSuggestion.TrimEnd(); + newSuggestion = newSuggestion.Replace("\r", ""); + ClearSuggestion(); - int lineN = GetCurrentTextLine(); + int lineN = GetCurrentTextLine(); - if (lineN < 0) return; + if (lineN < 0) return; - String untrim = buffer.CurrentSnapshot.GetLineFromLineNumber(lineN).GetText(); + String untrim = buffer.CurrentSnapshot.GetLineFromLineNumber(lineN).GetText(); - virtualText = ""; - if(String.IsNullOrWhiteSpace(untrim) && untrim.Length < caretPoint){ - virtualText = new string(' ', caretPoint - untrim.Length); - } - String line = untrim.TrimStart(); - int offset = untrim.Length - line.Length; + virtualText = ""; + if (String.IsNullOrWhiteSpace(untrim) && untrim.Length < caretPoint) + { + virtualText = new string(' ', caretPoint - untrim.Length); + } + String line = untrim.TrimStart(); + int offset = untrim.Length - line.Length; - caretPoint = Math.Max(0, caretPoint - offset); + caretPoint = Math.Max(0, caretPoint - offset); - String combineSuggestion = line + newSuggestion; - if (line.Length - caretPoint > 0) - { - String currentText = line.Substring(0, caretPoint); - combineSuggestion = currentText + newSuggestion; - userEndingText = line.Substring(caretPoint).Trim(); - var userIndex = newSuggestion.IndexOf(userEndingText); + String combineSuggestion = line + newSuggestion; + if (line.Length - caretPoint > 0) + { + String currentText = line.Substring(0, caretPoint); + combineSuggestion = currentText + newSuggestion; + userEndingText = line.Substring(caretPoint).Trim(); + var userIndex = newSuggestion.IndexOf(userEndingText); - if (userIndex < 0) - { - return; - } - userIndex += currentText.Length; + if (userIndex < 0) { return; } + userIndex += currentText.Length; - this.userIndex = userIndex; - isTextInsertion = true; - insertionPoint = line.Length - caretPoint; - } - else - { - isTextInsertion = false; - } - var suggestionLines = combineSuggestion.Split('\n'); -/* if(suggestionLines.Length > 1 && isTextInsertion){ - return; - } -*/ suggestion = new Tuple(combineSuggestion, suggestionLines); - Update(); + this.userIndex = userIndex; + isTextInsertion = true; + insertionPoint = line.Length - caretPoint; } + else { isTextInsertion = false; } + var suggestionLines = combineSuggestion.Split('\n'); + /* if(suggestionLines.Length > 1 && isTextInsertion){ + return; + } + */ + suggestion = new Tuple(combineSuggestion, suggestionLines); + Update(); + } - private void CaretUpdate(object sender, CaretPositionChangedEventArgs e) - { - if (showSuggestion && GetCurrentTextLine() != currentTextLineN) - { - ClearSuggestion(); - } - } + private void CaretUpdate(object sender, CaretPositionChangedEventArgs e) + { + if (showSuggestion && GetCurrentTextLine() != currentTextLineN) { ClearSuggestion(); } + } - private void LostFocus(object sender, EventArgs e) - { - ClearSuggestion(); - } + private void LostFocus(object sender, EventArgs e) { ClearSuggestion(); } - public SuggestionTagger(IWpfTextView view, ITextBuffer buffer) - { - this.stackPanel = new StackPanel(); + public SuggestionTagger(IWpfTextView view, ITextBuffer buffer) + { + this.stackPanel = new StackPanel(); - this.buffer = buffer; - this.snapshot = buffer.CurrentSnapshot; - view.TextBuffer.Changed += BufferChanged; - this.view = view; - this.adornmentLayer = view.GetAdornmentLayer("CodeiumAdornmentLayer"); + this.buffer = buffer; + this.snapshot = buffer.CurrentSnapshot; + view.TextBuffer.Changed += BufferChanged; + this.view = view; + this.adornmentLayer = view.GetAdornmentLayer("CodeiumAdornmentLayer"); - this.view.LayoutChanged += this.OnSizeChanged; + this.view.LayoutChanged += this.OnSizeChanged; - this.transparentBrush = new SolidColorBrush(); - this.transparentBrush.Opacity = 0; - this.greyBrush = new SolidColorBrush(Colors.Gray); - view.LostAggregateFocus += LostFocus; - view.Caret.PositionChanged += CaretUpdate; - } + this.transparentBrush = new SolidColorBrush(); + this.transparentBrush.Opacity = 0; + this.greyBrush = new SolidColorBrush(Colors.Gray); + view.LostAggregateFocus += LostFocus; + view.Caret.PositionChanged += CaretUpdate; + } - public bool IsSuggestionActive() - { - return showSuggestion; - } + public bool IsSuggestionActive() { return showSuggestion; } - public String GetSuggestion() - { - if (suggestion != null && showSuggestion) - { - return suggestion.Item1; - } - else - { - return ""; - } - } + public String GetSuggestion() + { + if (suggestion != null && showSuggestion) { return suggestion.Item1; } + else { return ""; } + } - //This an iterator that is used to iterate through all of the test tags - //tags are like html tags they mark places in the view to modify how those sections look - //Testtag is a tag that tells the editor to add empty space - public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + // This an iterator that is used to iterate through all of the test tags + // tags are like html tags they mark places in the view to modify how those sections look + // Testtag is a tag that tells the editor to add empty space + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + var currentSuggestion = suggestion; + if (!showSuggestion || currentSuggestion == null || currentSuggestion.Item2.Length <= 1) { - var currentSuggestion = suggestion; - if (!showSuggestion || currentSuggestion == null || currentSuggestion.Item2.Length <= 1) - { - yield break; - } - + yield break; + } - SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End).TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive); - ITextSnapshot currentSnapshot = spans[0].Snapshot; + SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End) + .TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive); + ITextSnapshot currentSnapshot = spans[0].Snapshot; - var line = currentSnapshot.GetLineFromLineNumber(currentTextLineN).Extent; - var span = new SnapshotSpan(line.End, line.End); + var line = currentSnapshot.GetLineFromLineNumber(currentTextLineN).Extent; + var span = new SnapshotSpan(line.End, line.End); - var snapshotLine = currentSnapshot.GetLineFromLineNumber(currentTextLineN); + var snapshotLine = currentSnapshot.GetLineFromLineNumber(currentTextLineN); - double height = view.LineHeight * (currentSuggestion.Item2.Length - 1); - double lineHeight = 0; + double height = view.LineHeight * (currentSuggestion.Item2.Length - 1); + double lineHeight = 0; - if (String.IsNullOrEmpty(line.GetText())) - { - lineHeight = view.LineHeight; - } - yield return new TagSpan(span, new SuggestionTag(0, 0, lineHeight, 0, height, PositionAffinity.Predecessor, stackPanel, this)); - } + if (String.IsNullOrEmpty(line.GetText())) { lineHeight = view.LineHeight; } + yield return new TagSpan( + span, + new SuggestionTag( + 0, 0, lineHeight, 0, height, PositionAffinity.Predecessor, stackPanel, this)); + } - public event EventHandler TagsChanged; + public event EventHandler TagsChanged; - //triggers when the editor text buffer changes - void BufferChanged(object sender, TextContentChangedEventArgs e) - { - // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). - if (e.After != buffer.CurrentSnapshot) - return; - - - - this.Update(); - } + // triggers when the editor text buffer changes + void BufferChanged(object sender, TextContentChangedEventArgs e) + { + // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll + // eventually get another change event). + if (e.After != buffer.CurrentSnapshot) return; - TextRunProperties GetTextFormat() - { - var line = view.TextViewLines.FirstVisibleLine; - return line.GetCharacterFormatting(line.Start); - } + this.Update(); + } - //used to set formatting of the displayed multi lines - public void FormatText(TextBlock block) - { - //var pos = snapshot.GetLineFromLineNumber(currentLineN).Start; + TextRunProperties GetTextFormat() + { + var line = view.TextViewLines.FirstVisibleLine; + return line.GetCharacterFormatting(line.Start); + } - var line = view.TextViewLines.FirstVisibleLine; - var format = line.GetCharacterFormatting(line.Start); - if (format != null) - { - block.FontFamily = format.Typeface.FontFamily; - block.FontSize = format.FontRenderingEmSize; - } - } + // used to set formatting of the displayed multi lines + public void FormatText(TextBlock block) + { + // var pos = snapshot.GetLineFromLineNumber(currentLineN).Start; - String ConvertTabsToSpaces(string text) - { - int tabSize = view.Options.GetTabSize(); - return Regex.Replace(text, "\t", new string(' ', tabSize)); - } - void FormatTextBlock(TextBlock textBlock) + var line = view.TextViewLines.FirstVisibleLine; + var format = line.GetCharacterFormatting(line.Start); + if (format != null) { - textBlock.FontStyle = FontStyles.Normal; - textBlock.FontWeight = FontWeights.Normal; + block.FontFamily = format.Typeface.FontFamily; + block.FontSize = format.FontRenderingEmSize; } + } - TextBlock CreateTextBox(string text, Brush textColour) - { - TextBlock textBlock = new TextBlock(); - textBlock.Inlines.Add(item: new Run(text) { Foreground = textColour }); - FormatTextBlock(textBlock); - return textBlock; - } + String ConvertTabsToSpaces(string text) + { + int tabSize = view.Options.GetTabSize(); + return Regex.Replace(text, "\t", new string(' ', tabSize)); + } + void FormatTextBlock(TextBlock textBlock) + { + textBlock.FontStyle = FontStyles.Normal; + textBlock.FontWeight = FontWeights.Normal; + } - void AddSuffixTextBlocks(int start, string line, string userText) - { + TextBlock CreateTextBox(string text, Brush textColour) + { + TextBlock textBlock = new TextBlock(); + textBlock.Inlines.Add(item: new Run(text) { Foreground = textColour }); + FormatTextBlock(textBlock); + return textBlock; + } - if (isTextInsertion && start > line.Length) - { - return; - } - int emptySpaceLength = userText.Length - userText.TrimStart().Length; - string emptySpace = ConvertTabsToSpaces(userText.Substring(0, emptySpaceLength)); - string editedUserText = emptySpace + userText.TrimStart(); - if (isTextInsertion) - { - editedUserText = emptySpace + line.Substring(0, start); - } - string remainder = line.Substring(start); - TextBlock textBlock = new TextBlock(); - textBlock.Inlines.Add(item: new Run(editedUserText) { Foreground = transparentBrush }); - textBlock.Inlines.Add(item: new Run(remainder) { Foreground = greyBrush }); + void AddSuffixTextBlocks(int start, string line, string userText) + { - stackPanel.Children.Add(textBlock); - } + if (isTextInsertion && start > line.Length) { return; } + int emptySpaceLength = userText.Length - userText.TrimStart().Length; + string emptySpace = ConvertTabsToSpaces(userText.Substring(0, emptySpaceLength)); + string editedUserText = emptySpace + userText.TrimStart(); + if (isTextInsertion) { editedUserText = emptySpace + line.Substring(0, start); } + string remainder = line.Substring(start); + TextBlock textBlock = new TextBlock(); + textBlock.Inlines.Add(item: new Run(editedUserText) { Foreground = transparentBrush }); + textBlock.Inlines.Add(item: new Run(remainder) { Foreground = greyBrush }); + + stackPanel.Children.Add(textBlock); + } - void AddInsertionTextBlock(int start, int end, string line) - { - if (line.Length <= suggestionIndex) - return; + void AddInsertionTextBlock(int start, int end, string line) + { + if (line.Length <= suggestionIndex) return; - string remainder = line.Substring(start, end - start); + string remainder = line.Substring(start, end - start); - ITextSnapshotLine snapshotLine = view.TextSnapshot.GetLineFromLineNumber(currentTextLineN); - var lineFormat = view.TextViewLines.GetCharacterBounds(snapshotLine.Start); + ITextSnapshotLine snapshotLine = view.TextSnapshot.GetLineFromLineNumber(currentTextLineN); + var lineFormat = view.TextViewLines.GetCharacterBounds(snapshotLine.Start); - var textBlock = CreateTextBox(remainder, greyBrush); - GetTagger().UpdateAdornment(textBlock); - } + var textBlock = CreateTextBox(remainder, greyBrush); + GetTagger().UpdateAdornment(textBlock); + } - //Updates the grey text - public void UpdateAdornment(IWpfTextView view, string userText, int suggestionStart) + // Updates the grey text + public void UpdateAdornment(IWpfTextView view, string userText, int suggestionStart) + { + stackPanel.Children.Clear(); + GetTagger().ClearAdornment(); + for (int i = suggestionStart; i < suggestion.Item2.Length; i++) { - stackPanel.Children.Clear(); - GetTagger().ClearAdornment(); - for (int i = suggestionStart; i < suggestion.Item2.Length; i++) + string line = suggestion.Item2[i]; + + if (i == 0) { - string line = suggestion.Item2[i]; + int offset = line.Length - line.TrimStart().Length; - if (i == 0) + if (isTextInsertion && suggestionIndex < userIndex) { - int offset = line.Length - line.TrimStart().Length; - - if (isTextInsertion && suggestionIndex < userIndex) + if (suggestionIndex > 0 && char.IsWhiteSpace(line[suggestionIndex - 1]) && + userText.Length > insertionPoint + 1 && + !char.IsWhiteSpace(userText[userText.Length - insertionPoint - 1])) { - if (suggestionIndex > 0 && char.IsWhiteSpace(line[suggestionIndex - 1]) && userText.Length > insertionPoint + 1 && !char.IsWhiteSpace(userText[userText.Length - insertionPoint - 1])) - { - suggestionIndex--; - } - AddInsertionTextBlock(suggestionIndex + offset, userIndex, line); - if (line.Length > userIndex + 1) - { - AddSuffixTextBlocks(userIndex + userEndingText.Trim().Length, line, userText); - } - else - { - stackPanel.Children.Add(CreateTextBox("", greyBrush)); - } + suggestionIndex--; } - else + AddInsertionTextBlock(suggestionIndex + offset, userIndex, line); + if (line.Length > userIndex + 1) { - if (String.IsNullOrEmpty(line)) - { - stackPanel.Children.Add(CreateTextBox("", greyBrush)); - } - else - { - String suggestedLine = virtualText.Length > 0 ? virtualText + line.TrimStart() : line; - AddSuffixTextBlocks(userText.Length > 0 ? suggestionIndex + offset : 0, suggestedLine, userText); - } + AddSuffixTextBlocks( + userIndex + userEndingText.Trim().Length, line, userText); } + else { stackPanel.Children.Add(CreateTextBox("", greyBrush)); } } else { - stackPanel.Children.Add(CreateTextBox(line, greyBrush)); + if (String.IsNullOrEmpty(line)) + { + stackPanel.Children.Add(CreateTextBox("", greyBrush)); + } + else + { + String suggestedLine = + virtualText.Length > 0 ? virtualText + line.TrimStart() : line; + AddSuffixTextBlocks(userText.Length > 0 ? suggestionIndex + offset : 0, + suggestedLine, + userText); + } } } + else { stackPanel.Children.Add(CreateTextBox(line, greyBrush)); } + } - this.adornmentLayer.RemoveAllAdornments(); - - //usually only happens the moment a bunch of text has rentered such as an undo operation - try - { - ITextSnapshotLine snapshotLine = view.TextSnapshot.GetLineFromLineNumber(currentTextLineN); - var start = view.TextViewLines.GetCharacterBounds(snapshotLine.Start); - - // Place the image in the top left hand corner of the line - Canvas.SetLeft(stackPanel, start.Left); - Canvas.SetTop(stackPanel, start.TextTop); - var span = snapshotLine.Extent; - // Add the image to the adornment layer and make it relative to the viewport - this.adornmentLayer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, stackPanel, null); + this.adornmentLayer.RemoveAllAdornments(); - } - catch (ArgumentOutOfRangeException e) - { - Debug.Write(e); - } + // usually only happens the moment a bunch of text has rentered such as an undo operation + try + { + ITextSnapshotLine snapshotLine = + view.TextSnapshot.GetLineFromLineNumber(currentTextLineN); + var start = view.TextViewLines.GetCharacterBounds(snapshotLine.Start); + + // Place the image in the top left hand corner of the line + Canvas.SetLeft(stackPanel, start.Left); + Canvas.SetTop(stackPanel, start.TextTop); + var span = snapshotLine.Extent; + // Add the image to the adornment layer and make it relative to the viewport + this.adornmentLayer.AddAdornment( + AdornmentPositioningBehavior.TextRelative, span, null, stackPanel, null); } - - //Adds grey text to display - private void OnSizeChanged(object sender, EventArgs e) + catch (ArgumentOutOfRangeException e) { - if (!showSuggestion) - { - return; - } + Debug.Write(e); + } + } - foreach (TextBlock block in stackPanel.Children) - { - FormatText(block); - } + // Adds grey text to display + private void OnSizeChanged(object sender, EventArgs e) + { + if (!showSuggestion) { return; } - ITextSnapshotLine snapshotLine = view.TextSnapshot.GetLineFromLineNumber(currentTextLineN); + foreach (TextBlock block in stackPanel.Children) + { + FormatText(block); + } - try - { - var start = view.TextViewLines.GetCharacterBounds(snapshotLine.Start); + ITextSnapshotLine snapshotLine = view.TextSnapshot.GetLineFromLineNumber(currentTextLineN); - InlineGreyTextTagger inlineTagger = GetTagger(); - inlineTagger.FormatText(GetTextFormat()); + try + { + var start = view.TextViewLines.GetCharacterBounds(snapshotLine.Start); - if (stackPanel.Children.Count > 0) - { - this.adornmentLayer.RemoveAllAdornments(); + InlineGreyTextTagger inlineTagger = GetTagger(); + inlineTagger.FormatText(GetTextFormat()); - var span = snapshotLine.Extent; + if (stackPanel.Children.Count > 0) + { + this.adornmentLayer.RemoveAllAdornments(); - // Place the image in the top left hand corner of the line - Canvas.SetLeft(stackPanel, start.Left); - Canvas.SetTop(element: stackPanel, start.TextTop); - var diff = start.Top - start.TextTop; - Debug.Print("Top = " + (start.Top.ToString()) + " TextTop = " + (start.TextTop.ToString()) + " bottom " + (start.TextBottom.ToString())); - // Add the image to the adornment layer and make it relative to the viewport - this.adornmentLayer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, stackPanel, null); - } + var span = snapshotLine.Extent; - } - catch (ArgumentOutOfRangeException) - { - Debug.Print("Error argument out of range"); + // Place the image in the top left hand corner of the line + Canvas.SetLeft(stackPanel, start.Left); + Canvas.SetTop(element: stackPanel, start.TextTop); + var diff = start.Top - start.TextTop; + Debug.Print("Top = " + (start.Top.ToString()) + + " TextTop = " + (start.TextTop.ToString()) + " bottom " + + (start.TextBottom.ToString())); + // Add the image to the adornment layer and make it relative to the viewport + this.adornmentLayer.AddAdornment( + AdornmentPositioningBehavior.TextRelative, span, null, stackPanel, null); } } - - - //Gets the line number of the caret - int GetCurrentTextLine() + catch (ArgumentOutOfRangeException) { - CaretPosition caretPosition = view.Caret.Position; + Debug.Print("Error argument out of range"); + } + } - var textPoint = caretPosition.Point.GetPoint(buffer, caretPosition.Affinity); + // Gets the line number of the caret + int GetCurrentTextLine() + { + CaretPosition caretPosition = view.Caret.Position; - if (!textPoint.HasValue) - { - return -1; - } + var textPoint = caretPosition.Point.GetPoint(buffer, caretPosition.Affinity); - return buffer.CurrentSnapshot.GetLineNumberFromPosition(textPoint.Value); - } + if (!textPoint.HasValue) { return -1; } - //update multiline data - public void Update() - { + return buffer.CurrentSnapshot.GetLineNumberFromPosition(textPoint.Value); + } - if (suggestion == null) - { - return; - } + // update multiline data + public void Update() + { - int textLineN = GetCurrentTextLine(); + if (suggestion == null) { return; } - if (textLineN < 0) - { - return; - } + int textLineN = GetCurrentTextLine(); - ITextSnapshot newSnapshot = buffer.CurrentSnapshot; - this.snapshot = newSnapshot; + if (textLineN < 0) { return; } - String untrimLine = newSnapshot.GetLineFromLineNumber(textLineN).GetText(); - String line = untrimLine.TrimStart(); + ITextSnapshot newSnapshot = buffer.CurrentSnapshot; + this.snapshot = newSnapshot; - //get line carat is on - //if suggestion matches line (possibly including preceding lines) - // show suggestion - //else - // clear suggestions + String untrimLine = newSnapshot.GetLineFromLineNumber(textLineN).GetText(); + String line = untrimLine.TrimStart(); - int suggestionIndex = StringCompare.CheckSuggestion(suggestion.Item1, line, isTextInsertion, insertionPoint); - if (suggestionIndex >= 0) - { - this.currentTextLineN = textLineN; - this.suggestionIndex = suggestionIndex; - ShowSuggestion(untrimLine, 0); - } - else - { - ClearSuggestion(); - } - } + // get line carat is on + // if suggestion matches line (possibly including preceding lines) + // show suggestion + // else + // clear suggestions - //Adds the grey text to the file replacing current line in the process - public bool CompleteText() + int suggestionIndex = + StringCompare.CheckSuggestion(suggestion.Item1, line, isTextInsertion, insertionPoint); + if (suggestionIndex >= 0) { - if(!showSuggestion || suggestion == null) - { - return false; - } - - int textLineN = GetCurrentTextLine(); + this.currentTextLineN = textLineN; + this.suggestionIndex = suggestionIndex; + ShowSuggestion(untrimLine, 0); + } + else { ClearSuggestion(); } + } - if (textLineN < 0 || textLineN != currentTextLineN) - { - return false; - } + // Adds the grey text to the file replacing current line in the process + public bool CompleteText() + { + if (!showSuggestion || suggestion == null) { return false; } - String untrimLine = this.snapshot.GetLineFromLineNumber(currentTextLineN).GetText(); - String line = untrimLine.Trim(); + int textLineN = GetCurrentTextLine(); - int suggestionLineN = StringCompare.CheckSuggestion(suggestion.Item1, line, isTextInsertion, insertionPoint); - if (suggestionLineN >= 0) - { - int diff = untrimLine.Length - untrimLine.TrimStart().Length; - string whitespace = String.IsNullOrWhiteSpace(untrimLine) ? "" : untrimLine.Substring(0, diff); - ReplaceText(whitespace + suggestion.Item1, currentTextLineN); - return true; - } + if (textLineN < 0 || textLineN != currentTextLineN) { return false; } - return false; - } + String untrimLine = this.snapshot.GetLineFromLineNumber(currentTextLineN).GetText(); + String line = untrimLine.Trim(); - //replaces text in the editor - void ReplaceText(string text, int lineN) + int suggestionLineN = + StringCompare.CheckSuggestion(suggestion.Item1, line, isTextInsertion, insertionPoint); + if (suggestionLineN >= 0) { - var oldLineN = lineN + suggestion.Item2.Length - 1; - bool insertion = isTextInsertion && suggestion.Item2.Length == 1; - var oldUserIndex = userIndex; - int offset = text.Length - suggestion.Item1.Length; - ClearSuggestion(); - SnapshotSpan span = this.snapshot.GetLineFromLineNumber(lineN).Extent; - ITextEdit edit = view.TextBuffer.CreateEdit(); - var spanLength = span.Length; - edit.Replace(span, text); - var newSnapshot = edit.Apply(); - - if (spanLength == 0 && text.Length > 0) - { - view.Caret.MoveTo(newSnapshot.GetLineFromLineNumber(oldLineN).End); - } + int diff = untrimLine.Length - untrimLine.TrimStart().Length; + string whitespace = + String.IsNullOrWhiteSpace(untrimLine) ? "" : untrimLine.Substring(0, diff); + ReplaceText(whitespace + suggestion.Item1, currentTextLineN); + return true; + } - if (insertion) - { - view.Caret.MoveTo(newSnapshot.GetLineFromLineNumber(oldLineN).Start.Add(oldUserIndex + offset)); + return false; + } - } + // replaces text in the editor + void ReplaceText(string text, int lineN) + { + var oldLineN = lineN + suggestion.Item2.Length - 1; + bool insertion = isTextInsertion && suggestion.Item2.Length == 1; + var oldUserIndex = userIndex; + int offset = text.Length - suggestion.Item1.Length; + ClearSuggestion(); + SnapshotSpan span = this.snapshot.GetLineFromLineNumber(lineN).Extent; + ITextEdit edit = view.TextBuffer.CreateEdit(); + var spanLength = span.Length; + edit.Replace(span, text); + var newSnapshot = edit.Apply(); + + if (spanLength == 0 && text.Length > 0) + { + view.Caret.MoveTo(newSnapshot.GetLineFromLineNumber(oldLineN).End); } - //sets up the suggestion for display - void ShowSuggestion(String text, int suggestionLineStart) + if (insertion) { - UpdateAdornment(view, text, suggestionLineStart); - - showSuggestion = true; - MarkDirty(); + view.Caret.MoveTo( + newSnapshot.GetLineFromLineNumber(oldLineN).Start.Add(oldUserIndex + offset)); } + } - //removes the suggestion - public void ClearSuggestion() - { - if (!showSuggestion) return; - InlineGreyTextTagger inlineTagger = GetTagger(); - inlineTagger.ClearAdornment(); - inlineTagger.MarkDirty(); - suggestion = null; - adornmentLayer.RemoveAllAdornments(); - showSuggestion = false; + // sets up the suggestion for display + void ShowSuggestion(String text, int suggestionLineStart) + { + UpdateAdornment(view, text, suggestionLineStart); - MarkDirty(); - } + showSuggestion = true; + MarkDirty(); + } - //triggers refresh of the screen - void MarkDirty() - { - GetTagger().MarkDirty(); - ITextSnapshot newSnapshot = buffer.CurrentSnapshot; - this.snapshot = newSnapshot; + // removes the suggestion + public void ClearSuggestion() + { + if (!showSuggestion) return; + InlineGreyTextTagger inlineTagger = GetTagger(); + inlineTagger.ClearAdornment(); + inlineTagger.MarkDirty(); + suggestion = null; + adornmentLayer.RemoveAllAdornments(); + showSuggestion = false; + + MarkDirty(); + } - if (view.TextViewLines == null) return; + // triggers refresh of the screen + void MarkDirty() + { + GetTagger().MarkDirty(); + ITextSnapshot newSnapshot = buffer.CurrentSnapshot; + this.snapshot = newSnapshot; - var changeStart = view.TextViewLines.FirstVisibleLine.Start; - var changeEnd = view.TextViewLines.LastVisibleLine.Start; + if (view.TextViewLines == null) return; - var startLine = view.TextSnapshot.GetLineFromPosition(changeStart); - var endLine = view.TextSnapshot.GetLineFromPosition(changeEnd); + var changeStart = view.TextViewLines.FirstVisibleLine.Start; + var changeEnd = view.TextViewLines.LastVisibleLine.Start; - var span = new SnapshotSpan(startLine.Start, endLine.EndIncludingLineBreak). - TranslateTo(targetSnapshot: newSnapshot, SpanTrackingMode.EdgePositive); + var startLine = view.TextSnapshot.GetLineFromPosition(changeStart); + var endLine = view.TextSnapshot.GetLineFromPosition(changeEnd); - //lines we are marking dirty - //currently all of them for simplicity - if (this.TagsChanged != null) - { - this.TagsChanged(this, new SnapshotSpanEventArgs(span)); - } - } + var span = new SnapshotSpan(startLine.Start, endLine.EndIncludingLineBreak) + .TranslateTo(targetSnapshot: newSnapshot, SpanTrackingMode.EdgePositive); + + // lines we are marking dirty + // currently all of them for simplicity + if (this.TagsChanged != null) { this.TagsChanged(this, new SnapshotSpanEventArgs(span)); } } +} - [Export(typeof(IViewTaggerProvider))] - [TagType(typeof(SuggestionTag))] - [ContentType("text")] - internal sealed class SuggestionProvider : IViewTaggerProvider - { +[Export(typeof(IViewTaggerProvider))] +[TagType(typeof(SuggestionTag))] +[ContentType("text")] +internal sealed class SuggestionProvider : IViewTaggerProvider +{ - [Export(typeof(AdornmentLayerDefinition))] - [Name("CodeiumAdornmentLayer")] - [Order(After = PredefinedAdornmentLayers.Caret)] - private AdornmentLayerDefinition editorAdornmentLayer; + [Export(typeof(AdornmentLayerDefinition))] + [Name("CodeiumAdornmentLayer")] + [Order(After = PredefinedAdornmentLayers.Caret)] + private AdornmentLayerDefinition editorAdornmentLayer; #pragma warning restore 649, 169 - //create a single tagger for each buffer. - //the MultilineGreyTextTagger displays the grey text in the editor. - public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + // create a single tagger for each buffer. + // the MultilineGreyTextTagger displays the grey text in the editor. + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) + where T : ITag + { + Func> sc = delegate() { - Func> sc = delegate () { return new SuggestionTagger((IWpfTextView)textView, buffer) as ITagger; }; - return buffer.Properties.GetOrCreateSingletonProperty>(typeof(SuggestionTagger), sc); - } - + return new SuggestionTagger((IWpfTextView)textView, buffer) as ITagger; + }; + return buffer.Properties.GetOrCreateSingletonProperty>(typeof(SuggestionTagger), + sc); } -} \ No newline at end of file +} +} diff --git a/CodeiumVS/SuggestionUI/TextViewListener.cs b/CodeiumVS/SuggestionUI/TextViewListener.cs index e969611..b1ef2a6 100644 --- a/CodeiumVS/SuggestionUI/TextViewListener.cs +++ b/CodeiumVS/SuggestionUI/TextViewListener.cs @@ -33,413 +33,400 @@ namespace CodeiumVS { - internal class CodeiumCompletionHandler : IOleCommandTarget, IDisposable - { - private readonly CodeiumVSPackage package; +internal class CodeiumCompletionHandler : IOleCommandTarget, IDisposable +{ + private readonly CodeiumVSPackage package; - private readonly ITextView _view; - private readonly IVsTextView _textViewAdapter; - private readonly ITextDocument _document; + private readonly ITextView _view; + private readonly IVsTextView _textViewAdapter; + private readonly ITextDocument _document; - private DateTime _lastRequest = DateTime.MinValue; + private DateTime _lastRequest = DateTime.MinValue; - private LangInfo _language; - private CancellationTokenSource? _requestTokenSource; - private readonly TimeSpan _intelliSenseDelay = TimeSpan.FromMilliseconds(250.0); + private LangInfo _language; + private CancellationTokenSource? _requestTokenSource; + private readonly TimeSpan _intelliSenseDelay = TimeSpan.FromMilliseconds(250.0); - private IOleCommandTarget m_nextCommandHandler; - private TextViewListener m_provider; - private CancellationTokenSource currentCancellTokenSource = null; - private CancellationToken currentCancellToken; - - private string currentCompletionID; - private bool hasCompletionUpdated; + private IOleCommandTarget m_nextCommandHandler; + private TextViewListener m_provider; + private CancellationTokenSource currentCancellTokenSource = null; + private CancellationToken currentCancellToken; - public async void GetCompletion() - { + private string currentCompletionID; + private bool hasCompletionUpdated; - if (!package.IsSignedIn()) - { - return; - } + public async void GetCompletion() + { - UpdateRequestTokenSource(new CancellationTokenSource()); + if (!package.IsSignedIn()) { return; } - SnapshotPoint? caretPoint = _view.Caret.Position.Point.GetPoint(textBuffer => (!textBuffer.ContentType.IsOfType("projection")), PositionAffinity.Successor); - if (!caretPoint.HasValue) - { - return; - } + UpdateRequestTokenSource(new CancellationTokenSource()); - var caretPosition = caretPoint.Value.Position; - await package.LogAsync($"RequestProposalsAsync - Language: {_language.Name}; Caret: {caretPosition}; ASCII: {_document.Encoding.IsSingleByte}"); + SnapshotPoint? caretPoint = _view.Caret.Position.Point.GetPoint( + textBuffer => (!textBuffer.ContentType.IsOfType("projection")), + PositionAffinity.Successor); + if (!caretPoint.HasValue) { return; } - string text = _view.TextSnapshot.GetText(); - int cursorPosition = _document.Encoding.IsSingleByte ? caretPosition : Utf16OffsetToUtf8Offset(text, caretPosition); + var caretPosition = caretPoint.Value.Position; + await package.LogAsync( + $"RequestProposalsAsync - Language: {_language.Name}; Caret: {caretPosition}; ASCII: {_document.Encoding.IsSingleByte}"); - if (cursorPosition > text.Length) - { - Debug.Print("Error Caret past text position"); - return; - } + string text = _view.TextSnapshot.GetText(); + int cursorPosition = _document.Encoding.IsSingleByte + ? caretPosition + : Utf16OffsetToUtf8Offset(text, caretPosition); - IList? list = await package.LanguageServer.GetCompletionsAsync( - _document.FilePath, - text, - _language, - cursorPosition, - _view.Options.GetOptionValue(DefaultOptions.NewLineCharacterOptionId), - _view.Options.GetOptionValue(DefaultOptions.TabSizeOptionId), - _view.Options.GetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId), - currentCancellTokenSource.Token); - - int lineN; - int characterN; - - int res = _textViewAdapter.GetCaretPos(out lineN, out characterN); - String line = _view.TextBuffer.CurrentSnapshot.GetLineFromLineNumber(lineN).GetText(); - Debug.Print("completions " + list.Count.ToString()); + if (cursorPosition > text.Length) + { + Debug.Print("Error Caret past text position"); + return; + } - if (res != VSConstants.S_OK) - { - return; - } + IList? list = await package.LanguageServer.GetCompletionsAsync( + _document.FilePath, + text, + _language, + cursorPosition, + _view.Options.GetOptionValue(DefaultOptions.NewLineCharacterOptionId), + _view.Options.GetOptionValue(DefaultOptions.TabSizeOptionId), + _view.Options.GetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId), + currentCancellTokenSource.Token); - if(list != null && list.Count > 0) - { - Debug.Print("completions " + list.Count.ToString()); + int lineN; + int characterN; - string prefix = line.Substring(0, Math.Min(characterN, line.Length)); - List> suggestions = ParseCompletion(list, text, line, prefix, characterN); + int res = _textViewAdapter.GetCaretPos(out lineN, out characterN); + String line = _view.TextBuffer.CurrentSnapshot.GetLineFromLineNumber(lineN).GetText(); + Debug.Print("completions " + list.Count.ToString()); - SuggestionTagger tagger = GetTagger(); - if (suggestions != null && suggestions.Count > 0 && tagger != null) - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - currentCompletionID = suggestions[0].Item2; + if (res != VSConstants.S_OK) { return; } - tagger.SetSuggestion(suggestions[0].Item1, characterN); - } + if (list != null && list.Count > 0) + { + Debug.Print("completions " + list.Count.ToString()); + + string prefix = line.Substring(0, Math.Min(characterN, line.Length)); + List> suggestions = + ParseCompletion(list, text, line, prefix, characterN); - await package.LogAsync("Generated " + list.Count + $" proposals"); + SuggestionTagger tagger = GetTagger(); + if (suggestions != null && suggestions.Count > 0 && tagger != null) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + currentCompletionID = suggestions[0].Item2; + tagger.SetSuggestion(suggestions[0].Item1, characterN); } + + await package.LogAsync("Generated " + list.Count + $" proposals"); } + } - List> ParseCompletion(IList completionItems, string text, string line, string prefix, int cursorPoint) + List> ParseCompletion(IList completionItems, + string text, string line, string prefix, + int cursorPoint) + { + if (completionItems == null || completionItems.Count == 0) { return null; } + + List> list = new(completionItems.Count); + for (int i = 0; i < completionItems.Count; i++) { - if (completionItems == null || completionItems.Count == 0) + Packets.CompletionItem completionItem = completionItems[i]; + int startOffset = (int)completionItem.range.startOffset; + int endOffset = (int)completionItem.range.endOffset; + if (completionItem.completionParts.Count == 0) { continue; } + int insertionStart = (int)completionItem.completionParts[0].offset; + + if (!_document.Encoding.IsSingleByte) { - return null; + startOffset = Utf8OffsetToUtf16Offset(text, startOffset); + endOffset = Utf8OffsetToUtf16Offset(text, endOffset); + insertionStart = Utf8OffsetToUtf16Offset(text, insertionStart); } - - List> list = new(completionItems.Count); - for (int i = 0; i < completionItems.Count; i++) + string end = text.Substring(endOffset); + String completionText = completionItems[i].completion.text; + if (!String.IsNullOrEmpty(end)) { - Packets.CompletionItem completionItem = completionItems[i]; - int startOffset = (int)completionItem.range.startOffset; - int endOffset = (int)completionItem.range.endOffset; - if(completionItem.completionParts.Count == 0) - { - continue; - } - int insertionStart = (int)completionItem.completionParts[0].offset; - - if (!_document.Encoding.IsSingleByte) - { - startOffset = Utf8OffsetToUtf16Offset(text, startOffset); - endOffset = Utf8OffsetToUtf16Offset(text, endOffset); - insertionStart = Utf8OffsetToUtf16Offset(text, insertionStart); - } - string end = text.Substring(endOffset); - String completionText = completionItems[i].completion.text; - if (!String.IsNullOrEmpty(end)) - { - int endNewline = end.IndexOf('\r'); - endNewline = endNewline <= -1 ? end.IndexOf('\n') : endNewline; - endNewline = endNewline <= -1 ? end.Length : endNewline; - - completionText = completionText + end.Substring(0, endNewline); - } - int offset = StringCompare.CheckSuggestion(completionText, prefix); - if (offset < 0) - { - continue; - } + int endNewline = end.IndexOf('\r'); + endNewline = endNewline <= -1 ? end.IndexOf('\n') : endNewline; + endNewline = endNewline <= -1 ? end.Length : endNewline; - completionText = completionText.Substring(offset); - string completionID = completionItem.completion.completionId; - var set = new Tuple(completionText, completionID); - list.Add(set); + completionText = completionText + end.Substring(0, endNewline); } + int offset = StringCompare.CheckSuggestion(completionText, prefix); + if (offset < 0) { continue; } - return list; + completionText = completionText.Substring(offset); + string completionID = completionItem.completion.completionId; + var set = new Tuple(completionText, completionID); + list.Add(set); } - private void OnSuggestionAccepted(String proposalId) - { - // unfortunately in the SDK version 17.5.33428.388, there are no - // SuggestionAcceptedEventArgs so we have to use reflection here - ThreadHelper.JoinableTaskFactory - .RunAsync(async delegate { - await CodeiumVSPackage.Instance.LogAsync($"Accepted completion {proposalId}"); - await CodeiumVSPackage.Instance.LanguageServer.AcceptCompletionAsync(proposalId); - }) - .FireAndForget(true); - } - - private void UpdateRequestTokenSource(CancellationTokenSource newSource) - { - if (currentCancellTokenSource != null) - { - currentCancellTokenSource.Cancel(); - currentCancellTokenSource.Dispose(); - } - currentCancellTokenSource = newSource; - } + return list; + } - public static int Utf16OffsetToUtf8Offset(string str, int utf16Offset) - { - return Encoding.UTF8.GetByteCount(str.ToCharArray(), 0, utf16Offset); - } + private void OnSuggestionAccepted(String proposalId) + { + // unfortunately in the SDK version 17.5.33428.388, there are no + // SuggestionAcceptedEventArgs so we have to use reflection here + ThreadHelper.JoinableTaskFactory + .RunAsync(async delegate { + await CodeiumVSPackage.Instance.LogAsync($"Accepted completion {proposalId}"); + await CodeiumVSPackage.Instance.LanguageServer.AcceptCompletionAsync(proposalId); + }) + .FireAndForget(true); + } - public static int Utf8OffsetToUtf16Offset(string str, int utf8Offset) + private void UpdateRequestTokenSource(CancellationTokenSource newSource) + { + if (currentCancellTokenSource != null) { - byte[] bytes = Encoding.UTF8.GetBytes(str); - return Encoding.UTF8.GetString(bytes.Take(utf8Offset).ToArray()).Length; + currentCancellTokenSource.Cancel(); + currentCancellTokenSource.Dispose(); } + currentCancellTokenSource = newSource; + } - internal CodeiumCompletionHandler(IVsTextView textViewAdapter, ITextView view, TextViewListener provider) - { - CodeiumVSPackage.EnsurePackageLoaded(); - package = CodeiumVSPackage.Instance; - _view = view; - m_provider = provider; - var topBuffer = view.BufferGraph.TopBuffer; - - var projectionBuffer = topBuffer as IProjectionBufferBase; + public static int Utf16OffsetToUtf8Offset(string str, int utf16Offset) + { + return Encoding.UTF8.GetByteCount(str.ToCharArray(), 0, utf16Offset); + } - ITextBuffer textBuffer = projectionBuffer != null ? projectionBuffer.SourceBuffers[0] : topBuffer; - provider.documentFactory.TryGetTextDocument(textBuffer, out _document); + public static int Utf8OffsetToUtf16Offset(string str, int utf8Offset) + { + byte[] bytes = Encoding.UTF8.GetBytes(str); + return Encoding.UTF8.GetString(bytes.Take(utf8Offset).ToArray()).Length; + } - _document.FileActionOccurred += OnFileActionOccurred; - _document.TextBuffer.ContentTypeChanged += OnContentTypeChanged; - RefreshLanguage(); + internal CodeiumCompletionHandler(IVsTextView textViewAdapter, ITextView view, + TextViewListener provider) + { + CodeiumVSPackage.EnsurePackageLoaded(); + package = CodeiumVSPackage.Instance; + _view = view; + m_provider = provider; + var topBuffer = view.BufferGraph.TopBuffer; + + var projectionBuffer = topBuffer as IProjectionBufferBase; + + ITextBuffer textBuffer = + projectionBuffer != null ? projectionBuffer.SourceBuffers[0] : topBuffer; + provider.documentFactory.TryGetTextDocument(textBuffer, out _document); + + _document.FileActionOccurred += OnFileActionOccurred; + _document.TextBuffer.ContentTypeChanged += OnContentTypeChanged; + RefreshLanguage(); + + _textViewAdapter = textViewAdapter; + // add the command to the command chain + textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler); + ShowIntellicodeMsg(); + } - _textViewAdapter = textViewAdapter; - //add the command to the command chain - textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler); - ShowIntellicodeMsg(); - } + private void OnContentTypeChanged(object sender, ContentTypeChangedEventArgs e) + { + RefreshLanguage(); + } - private void OnContentTypeChanged(object sender, ContentTypeChangedEventArgs e) - { - RefreshLanguage(); - } + private void OnFileActionOccurred(object sender, TextDocumentFileActionEventArgs e) + { + RefreshLanguage(); + } - private void OnFileActionOccurred(object sender, TextDocumentFileActionEventArgs e) - { - RefreshLanguage(); - } + private void RefreshLanguage() + { + _language = Mapper.GetLanguage(_document.TextBuffer.ContentType, + Path.GetExtension(_document.FilePath)?.Trim('.')); + } - private void RefreshLanguage() - { - _language = Mapper.GetLanguage(_document.TextBuffer.ContentType, - Path.GetExtension(_document.FilePath)?.Trim('.')); - } + void ClearSuggestion() + { + var tagger = GetTagger(); + if (tagger != null) { tagger.ClearSuggestion(); } + } - void ClearSuggestion() + // Used to detect when the user interacts with the intellisense popup + void CheckSuggestionUpdate(uint nCmdID) + { + switch (nCmdID) { - var tagger = GetTagger(); - if (tagger != null) + case ((uint)VSConstants.VSStd2KCmdID.UP): + case ((uint)VSConstants.VSStd2KCmdID.DOWN): + case ((uint)VSConstants.VSStd2KCmdID.PAGEUP): + case ((uint)VSConstants.VSStd2KCmdID.PAGEDN): + if (m_provider.CompletionBroker.IsCompletionActive(_view)) { - tagger.ClearSuggestion(); + hasCompletionUpdated = true; } - } - //Used to detect when the user interacts with the intellisense popup - void CheckSuggestionUpdate(uint nCmdID) - { - switch (nCmdID) - { - case ((uint)VSConstants.VSStd2KCmdID.UP): - case ((uint)VSConstants.VSStd2KCmdID.DOWN): - case ((uint)VSConstants.VSStd2KCmdID.PAGEUP): - case ((uint)VSConstants.VSStd2KCmdID.PAGEDN): - if (m_provider.CompletionBroker.IsCompletionActive(_view)) - { - hasCompletionUpdated = true; - } - - break; - case ((uint)VSConstants.VSStd2KCmdID.TAB): - case ((uint)VSConstants.VSStd2KCmdID.RETURN): - hasCompletionUpdated = false; - break; - } - } - private SuggestionTagger GetTagger() - { - var key = typeof(SuggestionTagger); - var props = _view.TextBuffer.Properties; - if (props.ContainsProperty(key)) - { - return props.GetProperty(key); - } - else - { - return null; - } + break; + case ((uint)VSConstants.VSStd2KCmdID.TAB): + case ((uint)VSConstants.VSStd2KCmdID.RETURN): + hasCompletionUpdated = false; + break; } + } + private SuggestionTagger GetTagger() + { + var key = typeof(SuggestionTagger); + var props = _view.TextBuffer.Properties; + if (props.ContainsProperty(key)) { return props.GetProperty(key); } + else { return null; } + } - public bool IsIntellicodeEnabled() - { - var vsSettingsManager = m_provider.ServiceProvider.GetService(typeof(SVsSettingsManager)) as IVsSettingsManager; + public bool IsIntellicodeEnabled() + { + var vsSettingsManager = + m_provider.ServiceProvider.GetService(typeof(SVsSettingsManager)) as IVsSettingsManager; + + vsSettingsManager.GetCollectionScopes(collectionPath: "ApplicationPrivateSettings", + out var applicationPrivateSettings); + vsSettingsManager.GetReadOnlySettingsStore(applicationPrivateSettings, + out IVsSettingsStore readStore); + var res2 = + readStore.GetString("ApplicationPrivateSettings\\Microsoft\\VisualStudio\\IntelliCode", + "WholeLineCompletions", + out var str); + return str != "1*System.Int64*2"; + } - vsSettingsManager.GetCollectionScopes(collectionPath: "ApplicationPrivateSettings", out var applicationPrivateSettings); - vsSettingsManager.GetReadOnlySettingsStore(applicationPrivateSettings, out IVsSettingsStore readStore); - var res2 = readStore.GetString("ApplicationPrivateSettings\\Microsoft\\VisualStudio\\IntelliCode", "WholeLineCompletions", out var str); - return str != "1*System.Int64*2"; + void ShowIntellicodeMsg() + { + if (IsIntellicodeEnabled()) + { + VsShellUtilities.ShowMessageBox( + this.package, + "Please disable IntelliCode to use Codeium. You can access Intellicode settings via Tools --> Options --> Intellicode.", + "Disable IntelliCode", + OLEMSGICON.OLEMSGICON_INFO, + OLEMSGBUTTON.OLEMSGBUTTON_OK, + OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } + } - void ShowIntellicodeMsg() + public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, + IntPtr pvaOut) + { + + // let the other handlers handle automation functions + if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { - if(IsIntellicodeEnabled()) { - VsShellUtilities.ShowMessageBox( - this.package, - "Please disable IntelliCode to use Codeium. You can access Intellicode settings via Tools --> Options --> Intellicode.", - "Disable IntelliCode", - OLEMSGICON.OLEMSGICON_INFO, - OLEMSGBUTTON.OLEMSGBUTTON_OK, - OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); - } + return m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); } - public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + // check for a commit character + if (!hasCompletionUpdated && nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { + var tagger = GetTagger(); - //let the other handlers handle automation functions - if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) - { - return m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); - } - - //check for a commit character - if (!hasCompletionUpdated && nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) + if (tagger != null) { - - var tagger = GetTagger(); - - if (tagger != null) + if (tagger.IsSuggestionActive() && tagger.CompleteText()) { - if (tagger.IsSuggestionActive() && tagger.CompleteText()) - { - ClearCompletionSessions(); - OnSuggestionAccepted(currentCompletionID); - return VSConstants.S_OK; - } - else - { - tagger.ClearSuggestion(); - } + ClearCompletionSessions(); + OnSuggestionAccepted(currentCompletionID); + return VSConstants.S_OK; } - - } - else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.CANCEL) - { - ClearSuggestion(); + else { tagger.ClearSuggestion(); } } + } + else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || + nCmdID == (uint)VSConstants.VSStd2KCmdID.CANCEL) + { + ClearSuggestion(); + } - CheckSuggestionUpdate(nCmdID); - - //make a copy of this so we can look at it after forwarding some commands - uint commandID = nCmdID; - char typedChar = char.MinValue; - - //make sure the input is a char before getting it - if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) - { - typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); - } - - //pass along the command so the char is added to the buffer - int retVal = m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); - bool handled = false; - - if (hasCompletionUpdated) - { - ClearSuggestion(); - } - //gets lsp completions on added character or deletions - if (!typedChar.Equals(char.MinValue) || commandID == (uint)VSConstants.VSStd2KCmdID.RETURN) - { - _ = Task.Run(() => GetCompletion()); - handled = true; - } - else if (commandID == (uint)VSConstants.VSStd2KCmdID.BACKSPACE || commandID == (uint)VSConstants.VSStd2KCmdID.DELETE) - { - ClearSuggestion(); - - _ = Task.Run(() => GetCompletion()); - handled = true; - } + CheckSuggestionUpdate(nCmdID); - if (handled) return VSConstants.S_OK; - return retVal; - } + // make a copy of this so we can look at it after forwarding some commands + uint commandID = nCmdID; + char typedChar = char.MinValue; - //clears the intellisense popup window - void ClearCompletionSessions() + // make sure the input is a char before getting it + if (pguidCmdGroup == VSConstants.VSStd2K && + nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { - m_provider.CompletionBroker.DismissAllSessions(_view); + typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } - public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) + // pass along the command so the char is added to the buffer + int retVal = + m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); + bool handled = false; + + if (hasCompletionUpdated) { ClearSuggestion(); } + // gets lsp completions on added character or deletions + if (!typedChar.Equals(char.MinValue) || commandID == (uint)VSConstants.VSStd2KCmdID.RETURN) { - return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + _ = Task.Run(() => GetCompletion()); + handled = true; } - - public void Dispose() + else if (commandID == (uint)VSConstants.VSStd2KCmdID.BACKSPACE || + commandID == (uint)VSConstants.VSStd2KCmdID.DELETE) { - _document.FileActionOccurred -= OnFileActionOccurred; - _document.TextBuffer.ContentTypeChanged -= OnContentTypeChanged; - UpdateRequestTokenSource(null); + ClearSuggestion(); + + _ = Task.Run(() => GetCompletion()); + handled = true; } + + if (handled) return VSConstants.S_OK; + return retVal; } - [Export(typeof(IVsTextViewCreationListener))] - [Name("TextViewListener")] - [ContentType("code")] - [TextViewRole(PredefinedTextViewRoles.Document)] + // clears the intellisense popup window + void ClearCompletionSessions() { m_provider.CompletionBroker.DismissAllSessions(_view); } - internal class TextViewListener : IVsTextViewCreationListener + public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) { - //adapters are used to get the IVsTextViewAdapter from the IVsTextView - [Import] - internal IVsEditorAdaptersFactoryService AdapterService = null; - - //service provider is used to get the IVsServiceProvider which is needed to access lsp - [Import] - internal SVsServiceProvider ServiceProvider { get; set; } - - //CompletionBroker is used by intellisense (popups) to provide completion items. - [Import] - internal ICompletionBroker CompletionBroker { get; set; } - - //document factory is used to get information about the current text document such as filepath, language, etc. - [Import] - internal ITextDocumentFactoryService documentFactory = null; - - public void VsTextViewCreated(IVsTextView textViewAdapter) - { - ITextView textView = AdapterService.GetWpfTextView(textViewAdapter); - if (textView == null) - return; + return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); + } - Func createCommandHandler = delegate () { return new CodeiumCompletionHandler(textViewAdapter, textView, this); }; - textView.Properties.GetOrCreateSingletonProperty(createCommandHandler); - } + public void Dispose() + { + _document.FileActionOccurred -= OnFileActionOccurred; + _document.TextBuffer.ContentTypeChanged -= OnContentTypeChanged; + UpdateRequestTokenSource(null); } } +[Export(typeof(IVsTextViewCreationListener))] +[Name("TextViewListener")] +[ContentType("code")] +[TextViewRole(PredefinedTextViewRoles.Document)] + +internal class TextViewListener : IVsTextViewCreationListener +{ + // adapters are used to get the IVsTextViewAdapter from the IVsTextView + [Import] + internal IVsEditorAdaptersFactoryService AdapterService = null; + + // service provider is used to get the IVsServiceProvider which is needed to access lsp + [Import] + internal SVsServiceProvider ServiceProvider { get; set; } + + // CompletionBroker is used by intellisense (popups) to provide completion items. + [Import] + internal ICompletionBroker CompletionBroker { + get; set; + } + + // document factory is used to get information about the current text document such as filepath, + // language, etc. + [Import] + internal ITextDocumentFactoryService documentFactory = null; + + public void VsTextViewCreated(IVsTextView textViewAdapter) + { + ITextView textView = AdapterService.GetWpfTextView(textViewAdapter); + if (textView == null) return; + + Func createCommandHandler = delegate() + { + return new CodeiumCompletionHandler(textViewAdapter, textView, this); + }; + textView.Properties.GetOrCreateSingletonProperty(createCommandHandler); + } +} +} diff --git a/CodeiumVS/source.extension.cs b/CodeiumVS/source.extension.cs index d47f505..ad00a7c 100644 --- a/CodeiumVS/source.extension.cs +++ b/CodeiumVS/source.extension.cs @@ -12,7 +12,7 @@ internal sealed partial class Vsix public const string Description = @"The modern coding superpower: free AI code acceleration plugin for your favorite languages. Type less. Code more. Ship faster."; public const string Language = "en-US"; - public const string Version = "1.6.22"; + public const string Version = "1.6.38"; public const string Author = "Codeium"; public const string Tags = ""; } diff --git a/CodeiumVS/source.extension.vsixmanifest b/CodeiumVS/source.extension.vsixmanifest index dbb6574..5e28dda 100644 --- a/CodeiumVS/source.extension.vsixmanifest +++ b/CodeiumVS/source.extension.vsixmanifest @@ -1,7 +1,7 @@ - + Codeium The modern coding superpower: free AI code acceleration plugin for your favorite languages. Type less. Code more. Ship faster. https://www.codeium.com