Browse Source

Add Ctrl+Space completion that automatically inserts usings.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
2793cc46eb
  1. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  2. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs
  3. 6
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs
  4. 54
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/ImportCompletionData.cs
  5. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/ExtensionMethods.cs
  6. 8
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/CSharpFullParseInformation.cs
  7. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
  8. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRedundantUsingIssue.cs
  9. 21
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs
  10. 23
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs
  11. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlFullParseInformation.cs
  12. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs
  13. 6
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ParserFoldingStrategy.cs
  14. 15
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
  15. 3
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ITextSource.cs
  16. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/TextSourceVersionProvider.cs
  17. 14
      src/Main/Base/Project/Parser/ParseInformation.cs
  18. 1
      src/Main/Core/Project/Src/Services/MessageService/MessageService.cs
  19. 1
      src/Main/SharpDevelop/Logging/ExceptionBox.cs
  20. 2
      src/Main/SharpDevelop/Parser/ParserServiceEntry.cs

1
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

@ -69,6 +69,7 @@ @@ -69,6 +69,7 @@
<Compile Include="Src\Completion\CSharpCompletionContext.cs" />
<Compile Include="Src\Completion\CSharpInsightItem.cs" />
<Compile Include="Src\Completion\CSharpMethodInsight.cs" />
<Compile Include="Src\Completion\ImportCompletionData.cs" />
<Compile Include="Src\Completion\OverrideCompletionData.cs" />
<Compile Include="Src\Completion\SegmentTrackingOutputFormatter.cs" />
<Compile Include="Src\FormattingStrategy\CSharpFormatter.cs" />

1
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs

@ -60,6 +60,7 @@ namespace CSharpBinding.Completion @@ -60,6 +60,7 @@ namespace CSharpBinding.Completion
triggerWordLength = 0;
}
completionData = cce.GetCompletionData(startPos, true);
completionData = completionData.Concat(cce.GetImportCompletionData(startPos));
} else {
startPos = editor.Caret.Offset;
if (char.IsLetterOrDigit (completionChar) || completionChar == '_') {

6
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs

@ -115,7 +115,11 @@ namespace CSharpBinding.Completion @@ -115,7 +115,11 @@ namespace CSharpBinding.Completion
ICompletionData ICompletionDataFactory.CreateImportCompletionData(IType type, bool useFullName)
{
return new CompletionData("TODO: import completion");
ITypeDefinition typeDef = type.GetDefinition();
if (typeDef != null)
return new ImportCompletionData(typeDef, contextAtCaret, useFullName);
else
throw new InvalidOperationException("Should never happen");
}
#endregion

54
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/ImportCompletionData.cs

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
//
using System;
using System.Linq;
using System.Threading;
using CSharpBinding.Refactoring;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace CSharpBinding.Completion
{
class ImportCompletionData : EntityCompletionData
{
string insertUsing;
string insertionText;
public ImportCompletionData(ITypeDefinition typeDef, CSharpTypeResolveContext contextAtCaret, bool useFullName)
: base(typeDef)
{
this.Description = "using " + typeDef.Namespace + ";";
if (useFullName) {
var astBuilder = new TypeSystemAstBuilder(new CSharpResolver(contextAtCaret));
insertionText = astBuilder.ConvertType(typeDef).GetText();
} else {
insertionText = typeDef.Name;
insertUsing = typeDef.Namespace;
}
}
public override void Complete(CompletionContext context)
{
context.Editor.Document.Replace(context.StartOffset, context.Length, insertionText);
context.EndOffset = context.StartOffset + insertionText.Length;
if (insertUsing != null) {
SD.Log.Debug("Insert using '" + insertUsing + "'");
var refactoringContext = SDRefactoringContext.Create(context.Editor, CancellationToken.None);
using (var script = refactoringContext.StartScript()) {
// TODO: sort usings; insert inside namespace if other usings are there; etc.
var prevUsing = refactoringContext.RootNode.Children.LastOrDefault(p => p is UsingDeclaration);
if (prevUsing != null) {
script.InsertAfter(prevUsing, new UsingDeclaration(insertUsing));
}
}
}
}
}
}

1
src/AddIns/BackendBindings/CSharpBinding/Project/Src/ExtensionMethods.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using CSharpBinding.Parser;
using CSharpBinding.Refactoring;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;

8
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/CSharpFullParseInformation.cs

@ -18,17 +18,15 @@ namespace CSharpBinding.Parser @@ -18,17 +18,15 @@ namespace CSharpBinding.Parser
public class CSharpFullParseInformation : ParseInformation
{
readonly SyntaxTree compilationUnit;
readonly ITextSourceVersion parsedVersion;
internal List<NewFolding> newFoldings;
public CSharpFullParseInformation(CSharpUnresolvedFile unresolvedFile, ITextSourceVersion parsedVersion, SyntaxTree compilationUnit)
: base(unresolvedFile, isFullParseInformation: true)
: base(unresolvedFile, parsedVersion, isFullParseInformation: true)
{
if (unresolvedFile == null)
throw new ArgumentNullException("unresolvedFile");
if (compilationUnit == null)
throw new ArgumentNullException("compilationUnit");
this.parsedVersion = parsedVersion;
this.compilationUnit = compilationUnit;
}
@ -40,10 +38,6 @@ namespace CSharpBinding.Parser @@ -40,10 +38,6 @@ namespace CSharpBinding.Parser
get { return compilationUnit; }
}
public ITextSourceVersion ParsedVersion {
get { return parsedVersion; }
}
public CSharpAstResolver GetResolver(ICompilation compilation)
{
return (CSharpAstResolver)compilation.CacheManager.GetOrAddShared(

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs

@ -85,7 +85,7 @@ namespace CSharpBinding.Parser @@ -85,7 +85,7 @@ namespace CSharpBinding.Parser
if (fullParseInformationRequested)
parseInfo = new CSharpFullParseInformation(file, fileContent.Version, cu);
else
parseInfo = new ParseInformation(file, fullParseInformationRequested);
parseInfo = new ParseInformation(file, fileContent.Version, fullParseInformationRequested);
IDocument document = fileContent as IDocument;
AddCommentTags(cu, parseInfo.TagComments, fileContent, parseInfo.FileName, ref document);

1
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRedundantUsingIssue.cs

@ -11,6 +11,7 @@ namespace CSharpBinding.Refactoring @@ -11,6 +11,7 @@ namespace CSharpBinding.Refactoring
public SDRedundantUsingIssue()
{
base.NamespacesToKeep.Add("System");
base.NamespacesToKeep.Add("System.Linq");
}
}
}

21
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs

@ -6,6 +6,7 @@ using System.ComponentModel.Design; @@ -6,6 +6,7 @@ using System.ComponentModel.Design;
using System.Threading;
using CSharpBinding.Parser;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
@ -29,6 +30,26 @@ namespace CSharpBinding.Refactoring @@ -29,6 +30,26 @@ namespace CSharpBinding.Refactoring
volatile IDocument document;
int selectionStart, selectionLength;
public static SDRefactoringContext Create(ITextEditor editor, CancellationToken cancellationToken)
{
return Create(editor.FileName, editor.Document, editor.Caret.Location, cancellationToken);
}
public static SDRefactoringContext Create(FileName fileName, ITextSource textSource, TextLocation location, CancellationToken cancellationToken)
{
var parseInfo = SD.ParserService.Parse(fileName, textSource, cancellationToken: cancellationToken) as CSharpFullParseInformation;
var compilation = SD.ParserService.GetCompilationForFile(fileName);
CSharpAstResolver resolver;
if (parseInfo != null) {
resolver = parseInfo.GetResolver(compilation);
} else {
// create dummy refactoring context
resolver = new CSharpAstResolver(compilation, new SyntaxTree());
}
var context = new SDRefactoringContext(textSource, resolver, new TextLocation(0, 0), 0, 0, cancellationToken);
return context;
}
public SDRefactoringContext(ITextSource textSource, CSharpAstResolver resolver, TextLocation location, int selectionStart, int selectionLength, CancellationToken cancellationToken)
: base(resolver, cancellationToken)
{

23
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs

@ -151,12 +151,7 @@ namespace CSharpBinding.Refactoring @@ -151,12 +151,7 @@ namespace CSharpBinding.Refactoring
SearchedFile SearchForIssues(FileName fileName, ITextSource fileContent, IEnumerable<IssueManager.IssueProvider> providers, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var parseInfo = SD.ParserService.Parse(fileName, fileContent, cancellationToken: cancellationToken) as CSharpFullParseInformation;
if (parseInfo == null)
return null;
var compilation = SD.ParserService.GetCompilationForFile(fileName);
var resolver = parseInfo.GetResolver(compilation);
var context = new SDRefactoringContext(fileContent, resolver, new TextLocation(0, 0), 0, 0, cancellationToken);
var context = SDRefactoringContext.Create(fileName, fileContent, TextLocation.Empty, cancellationToken);
ReadOnlyDocument document = null;
IHighlighter highlighter = null;
var results = new List<SearchResultMatch>();
@ -208,13 +203,8 @@ namespace CSharpBinding.Refactoring @@ -208,13 +203,8 @@ namespace CSharpBinding.Refactoring
documentWasLoadedFromDisk = true;
document = new TextDocument(SD.FileService.GetFileContent(fileName)) { FileName = fileName };
}
var parseInfo = SD.ParserService.Parse(fileName, document, cancellationToken: cancellationToken) as CSharpFullParseInformation;
if (parseInfo == null)
return Enumerable.Empty<SearchResultMatch>();
var compilation = SD.ParserService.GetCompilationForFile(fileName);
var resolver = parseInfo.GetResolver(compilation);
var context = new SDRefactoringContext(document, resolver, new TextLocation(0, 0), 0, 0, cancellationToken);
var context = SDRefactoringContext.Create(fileName, document, TextLocation.Empty, cancellationToken);
List<CodeIssue> allIssues = new List<CodeIssue>();
bool documentWasChanged = false;
foreach (var provider in providers) {
@ -231,13 +221,8 @@ namespace CSharpBinding.Refactoring @@ -231,13 +221,8 @@ namespace CSharpBinding.Refactoring
}
}
documentWasChanged = true;
// Update parseInfo etc. now that we've modified the document
parseInfo = SD.ParserService.Parse(fileName, document, cancellationToken: cancellationToken) as CSharpFullParseInformation;
if (parseInfo == null)
return Enumerable.Empty<SearchResultMatch>();
compilation = SD.ParserService.GetCompilationForFile(fileName);
resolver = parseInfo.GetResolver(compilation);
context = new SDRefactoringContext(document, resolver, new TextLocation(0, 0), 0, 0, cancellationToken);
// Update context now that we've modified the document
context = SDRefactoringContext.Create(fileName, document, TextLocation.Empty, cancellationToken);
// Find remaining issues:
allIssues.AddRange(provider.GetIssues(context));
} else {

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlFullParseInformation.cs

@ -14,7 +14,7 @@ namespace ICSharpCode.XamlBinding @@ -14,7 +14,7 @@ namespace ICSharpCode.XamlBinding
readonly ITextSource text;
public XamlFullParseInformation(XamlUnresolvedFile unresolvedFile, AXmlDocument document, ITextSource text)
: base(unresolvedFile, true)
: base(unresolvedFile, text.Version, true)
{
if (unresolvedFile == null)
throw new ArgumentNullException("unresolvedFile");

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs

@ -70,7 +70,7 @@ namespace ICSharpCode.XamlBinding @@ -70,7 +70,7 @@ namespace ICSharpCode.XamlBinding
if (fullParseInformationRequested)
parseInfo = new XamlFullParseInformation(unresolvedFile, document, fileContent);
else
parseInfo = new ParseInformation(unresolvedFile, false);
parseInfo = new ParseInformation(unresolvedFile, fileContent.Version, false);
AddTagComments(document, parseInfo, fileContent);
return parseInfo;
}

6
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ParserFoldingStrategy.cs

@ -8,6 +8,7 @@ using System.Linq; @@ -8,6 +8,7 @@ using System.Linq;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Parser;
@ -44,6 +45,11 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -44,6 +45,11 @@ namespace ICSharpCode.AvalonEdit.AddIn
public void UpdateFoldings(ParseInformation parseInfo)
{
if (!textArea.Document.Version.Equals(parseInfo.ParsedVersion)) {
SD.Log.Debug("Folding update ignored; parse information is outdated version");
return;
}
SD.Log.Debug("Update Foldings");
int firstErrorOffset = -1;
IEnumerable<NewFolding> newFoldings = parseInfo.GetFoldings(textArea.Document, out firstErrorOffset);
newFoldings = newFoldings.OrderBy(f => f.StartOffset);

15
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs

@ -69,6 +69,10 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -69,6 +69,10 @@ namespace ICSharpCode.AvalonEdit.Highlighting
protected virtual void DeregisterServices(TextView textView)
{
if (highlighter != null) {
if (isInHighlightingGroup) {
highlighter.EndHighlighting();
isInHighlightingGroup = false;
}
highlighter.HighlightingStateChanged -= OnHighlightStateChanged;
// remove highlighter if it is registered
if (textView.Services.GetService(typeof(IHighlighter)) == highlighter)
@ -136,6 +140,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -136,6 +140,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting
this.textView = null;
}
bool isInHighlightingGroup;
void textView_VisualLineConstructionStarting(object sender, VisualLineConstructionStartEventArgs e)
{
if (highlighter != null) {
@ -144,7 +150,11 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -144,7 +150,11 @@ namespace ICSharpCode.AvalonEdit.Highlighting
// We need to detect this case and issue a redraw (through TextViewDocumentHighligher.OnHighlightStateChanged)
// before the visual line construction reuses existing lines that were built using the invalid highlighting state.
lineNumberBeingColorized = e.FirstLineInView.LineNumber - 1;
highlighter.BeginHighlighting();
if (!isInHighlightingGroup) {
// avoid opening group twice if there was an exception during the previous visual line construction
highlighter.BeginHighlighting();
isInHighlightingGroup = true;
}
highlighter.UpdateHighlightingState(lineNumberBeingColorized);
lineNumberBeingColorized = 0;
}
@ -152,8 +162,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -152,8 +162,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting
void textView_VisualLinesChanged(object sender, EventArgs e)
{
if (highlighter != null) {
if (highlighter != null && isInHighlightingGroup) {
highlighter.EndHighlighting();
isInHighlightingGroup = false;
}
}

3
src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ITextSource.cs

@ -186,6 +186,9 @@ namespace ICSharpCode.NRefactory.Editor @@ -186,6 +186,9 @@ namespace ICSharpCode.NRefactory.Editor
/// <summary>
/// Gets whether this checkpoint belongs to the same document as the other checkpoint.
/// </summary>
/// <remarks>
/// Returns false when given <c>null</c>.
/// </remarks>
bool BelongsToSameDocumentAs(ITextSourceVersion other);
/// <summary>

2
src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/TextSourceVersionProvider.cs

@ -79,8 +79,6 @@ namespace ICSharpCode.NRefactory.Editor @@ -79,8 +79,6 @@ namespace ICSharpCode.NRefactory.Editor
public bool BelongsToSameDocumentAs(ITextSourceVersion other)
{
if (other == null)
throw new ArgumentNullException("other");
Version o = other as Version;
return o != null && provider == o.provider;
}

14
src/Main/Base/Project/Parser/ParseInformation.cs

@ -21,13 +21,15 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -21,13 +21,15 @@ namespace ICSharpCode.SharpDevelop.Parser
{
readonly IUnresolvedFile unresolvedFile;
IList<TagComment> tagComments = new List<TagComment>();
readonly ITextSourceVersion parsedVersion;
readonly bool isFullParseInformation;
public ParseInformation(IUnresolvedFile unresolvedFile, bool isFullParseInformation)
public ParseInformation(IUnresolvedFile unresolvedFile, ITextSourceVersion parsedVersion, bool isFullParseInformation)
{
if (unresolvedFile == null)
throw new ArgumentNullException("unresolvedFile");
this.unresolvedFile = unresolvedFile;
this.parsedVersion = parsedVersion;
this.isFullParseInformation = isFullParseInformation;
}
@ -52,6 +54,10 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -52,6 +54,10 @@ namespace ICSharpCode.SharpDevelop.Parser
get { return tagComments; }
}
public ITextSourceVersion ParsedVersion {
get { return parsedVersion; }
}
#region Folding
/// <summary>
/// Gets whether this <see cref="ParseInformation"/> instance supports folding.
@ -66,8 +72,10 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -66,8 +72,10 @@ namespace ICSharpCode.SharpDevelop.Parser
/// The base implementation of this method uses the unresolved file to produce
/// fold markers for all type defintions and methods.
/// </summary>
/// <param name="document"></param>
/// <param name="firstErrorOffset"></param>
/// <param name="document">The document for which to get the foldings</param>
/// <param name="firstErrorOffset">The first position of a parse error. Existing foldings starting after
/// this offset will be kept even if they don't appear in <paramref name="newFoldings"/>.
/// Use -1 for this parameter if there were no parse errors.</param>
/// <returns></returns>
public virtual IEnumerable<NewFolding> GetFoldings(IDocument document, out int firstErrorOffset)
{

1
src/Main/Core/Project/Src/Services/MessageService/MessageService.cs

@ -49,7 +49,6 @@ namespace ICSharpCode.Core @@ -49,7 +49,6 @@ namespace ICSharpCode.Core
/// </summary>
public static void ShowWarning(string message)
{
LoggingService.Warn(message);
Service.ShowWarning(message);
}

1
src/Main/SharpDevelop/Logging/ExceptionBox.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.SharpDevelop.Logging @@ -41,6 +41,7 @@ namespace ICSharpCode.SharpDevelop.Logging
static void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
LoggingService.Error("Unhandled WPF exception", e.Exception);
ShowErrorBox(e.Exception, "Unhandled WPF exception", false);
e.Handled = true;
}

2
src/Main/SharpDevelop/Parser/ParserServiceEntry.cs

@ -348,7 +348,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -348,7 +348,7 @@ namespace ICSharpCode.SharpDevelop.Parser
if (unresolvedFile == null)
throw new ArgumentNullException("unresolvedFile");
FreezableHelper.Freeze(unresolvedFile);
var newParseInfo = new ParseInformation(unresolvedFile, false);
var newParseInfo = new ParseInformation(unresolvedFile, null, false);
lock (this) {
int index = FindIndexForProject(project);
if (index >= 0) {

Loading…
Cancel
Save