|
|
@ -23,205 +23,22 @@ namespace ICSharpCode.RubyBinding |
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Form's designer generator for the Ruby language.
|
|
|
|
/// Form's designer generator for the Ruby language.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public class RubyDesignerGenerator : IScriptingDesignerGenerator |
|
|
|
public class RubyDesignerGenerator : ScriptingDesignerGenerator |
|
|
|
{ |
|
|
|
{ |
|
|
|
FormsDesignerViewContent viewContent; |
|
|
|
|
|
|
|
ITextEditorOptions textEditorOptions; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public RubyDesignerGenerator(ITextEditorOptions textEditorOptions) |
|
|
|
public RubyDesignerGenerator(ITextEditorOptions textEditorOptions) |
|
|
|
|
|
|
|
: base(textEditorOptions) |
|
|
|
{ |
|
|
|
{ |
|
|
|
this.textEditorOptions = textEditorOptions; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Gets the Ruby code dom provider.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public CodeDomProvider CodeDomProvider { |
|
|
|
|
|
|
|
get { return null; } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Attach(FormsDesignerViewContent viewContent) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
this.viewContent = viewContent; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Detach() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
this.viewContent = null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public IEnumerable<OpenedFile> GetSourceFiles(out OpenedFile designerCodeFile) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
designerCodeFile = this.ViewContent.PrimaryFile; |
|
|
|
|
|
|
|
return new [] {designerCodeFile}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void MergeFormChanges(CodeCompileUnit unit) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void NotifyFormRenamed(string newName) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Updates the InitializeComponent method's body with the generated code.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public void MergeRootComponentChanges(IDesignerHost host, IDesignerSerializationManager serializationManager) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ParseInformation parseInfo = ParseFile(); |
|
|
|
|
|
|
|
Merge(host, ViewContent.DesignerCodeFileDocument, parseInfo.CompilationUnit, textEditorOptions, serializationManager); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Merges the generated code into the specified document.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <param name="component">The designer host.</param>
|
|
|
|
|
|
|
|
/// <param name="document">The document that the generated code will be merged into.</param>
|
|
|
|
|
|
|
|
/// <param name="parseInfo">The current compilation unit for the <paramref name="document"/>.</param>
|
|
|
|
|
|
|
|
public static void Merge(IDesignerHost host, IDocument document, ICompilationUnit compilationUnit, ITextEditorOptions textEditorOptions, IDesignerSerializationManager serializationManager) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Get the document's initialize components method.
|
|
|
|
|
|
|
|
IMethod method = GetInitializeComponents(compilationUnit); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Generate the Ruby source code.
|
|
|
|
|
|
|
|
RubyCodeDomSerializer serializer = new RubyCodeDomSerializer(textEditorOptions.IndentationString); |
|
|
|
|
|
|
|
int indent = method.Region.BeginColumn; |
|
|
|
|
|
|
|
if (textEditorOptions.ConvertTabsToSpaces) { |
|
|
|
|
|
|
|
indent = (indent / textEditorOptions.IndentationSize); |
|
|
|
|
|
|
|
if (textEditorOptions.IndentationSize > 1) { |
|
|
|
|
|
|
|
indent += 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
string rootNamespace = GetProjectRootNamespace(compilationUnit); |
|
|
|
|
|
|
|
string methodBody = serializer.GenerateInitializeComponentMethodBody(host, serializationManager, rootNamespace, indent); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Merge the code.
|
|
|
|
|
|
|
|
DomRegion methodRegion = GetBodyRegionInDocument(method); |
|
|
|
|
|
|
|
int startOffset = GetStartOffset(document, methodRegion); |
|
|
|
|
|
|
|
int endOffset = GetEndOffset(document, methodRegion); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
document.Replace(startOffset, endOffset - startOffset, methodBody); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Inserts an event handler.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public bool InsertComponentEvent(IComponent component, EventDescriptor edesc, string eventMethodName, string body, out string file, out int position) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
position = GetExistingEventHandler(eventMethodName); |
|
|
|
|
|
|
|
if (position == -1) { |
|
|
|
|
|
|
|
// Ensure the text editor has the latest version
|
|
|
|
|
|
|
|
// of the source code before we insert any new code.
|
|
|
|
|
|
|
|
viewContent.MergeFormChanges(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Insert the event handler at the end of the class with an extra
|
|
|
|
|
|
|
|
// new line before it.
|
|
|
|
|
|
|
|
IDocument doc = viewContent.DesignerCodeFileDocument; |
|
|
|
|
|
|
|
string eventHandler = CreateEventHandler(eventMethodName, body, textEditorOptions.IndentationString); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IDocumentLine classEndLine = GetClassEndLine(doc); |
|
|
|
|
|
|
|
InsertEventHandlerBeforeLine(doc, eventHandler, classEndLine); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set position so it points to the line
|
|
|
|
|
|
|
|
// where the event handler was inserted.
|
|
|
|
|
|
|
|
position = classEndLine.LineNumber; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set the filename so it refers to the form being designed.
|
|
|
|
|
|
|
|
file = viewContent.DesignerCodeFile.FileName; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IDocumentLine GetClassEndLine(IDocument doc) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int line = doc.TotalNumberOfLines; |
|
|
|
|
|
|
|
while (line > 0) { |
|
|
|
|
|
|
|
IDocumentLine documentLine = doc.GetLine(line); |
|
|
|
|
|
|
|
if (documentLine.Text.Trim() == "end") { |
|
|
|
|
|
|
|
return documentLine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
line--; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return doc.GetLine(doc.TotalNumberOfLines); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void InsertEventHandlerBeforeLine(IDocument doc, string eventHandler, IDocumentLine classEndLine) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
string newContent = "\r\n" + eventHandler + "\r\n"; |
|
|
|
|
|
|
|
int offset = classEndLine.Offset; |
|
|
|
|
|
|
|
doc.Insert(offset, newContent); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Returns a list of method names that could be used as an
|
|
|
|
|
|
|
|
/// event handler with the specified event.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public ICollection GetCompatibleMethods(EventDescriptor edesc) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Get the form or user control class.
|
|
|
|
|
|
|
|
ParseInformation parseInfo = ParseFile(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Look at the form's methods and see which are compatible.
|
|
|
|
|
|
|
|
ArrayList methods = new ArrayList(); |
|
|
|
|
|
|
|
IClass c = GetClass(parseInfo.CompilationUnit); |
|
|
|
|
|
|
|
foreach (IMethod method in c.Methods) { |
|
|
|
|
|
|
|
if (method.Parameters.Count == 2) { |
|
|
|
|
|
|
|
methods.Add(method.Name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return methods; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Gets the non-generated InitializeComponents from the compilation unit.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public static IMethod GetInitializeComponents(ICompilationUnit unit) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foreach (IClass c in unit.Classes) { |
|
|
|
|
|
|
|
if (FormsDesignerSecondaryDisplayBinding.BaseClassIsFormOrControl(c)) { |
|
|
|
|
|
|
|
IMethod method = FormsDesignerSecondaryDisplayBinding.GetInitializeComponents(c); |
|
|
|
|
|
|
|
if (method != null) { |
|
|
|
|
|
|
|
return method; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
public override IScriptingCodeDomSerializer CreateCodeDomSerializer(ITextEditorOptions options) |
|
|
|
/// Converts from the DOM region to a document region.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public static DomRegion GetBodyRegionInDocument(IMethod method) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
DomRegion bodyRegion = method.BodyRegion; |
|
|
|
return new RubyCodeDomSerializer(options.IndentationString); |
|
|
|
return new DomRegion(bodyRegion.BeginLine + 1, 1, bodyRegion.EndLine, 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Gets the view content attached to this generator.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public FormsDesignerViewContent ViewContent { |
|
|
|
|
|
|
|
get { return viewContent; } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// The default implementation calls the ParserService.ParseFile. This
|
|
|
|
|
|
|
|
/// method is overridable so the class can be easily tested without
|
|
|
|
|
|
|
|
/// the ParserService being required.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
protected virtual ParseInformation ParseFile(string fileName, string textContent) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return ParserService.ParseFile(fileName, new StringTextBuffer(textContent)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Returns the generated event handler.
|
|
|
|
/// Returns the generated event handler.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="indentation">The indent string to use for the event handler.</param>
|
|
|
|
public override string CreateEventHandler(string eventMethodName, string body, string indentation) |
|
|
|
protected string CreateEventHandler(string eventMethodName, string body, string indentation) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
if (String.IsNullOrEmpty(body)) { |
|
|
|
if (String.IsNullOrEmpty(body)) { |
|
|
|
body = String.Empty; |
|
|
|
body = String.Empty; |
|
|
@ -235,7 +52,7 @@ namespace ICSharpCode.RubyBinding |
|
|
|
eventHandler.Append("(sender, e)"); |
|
|
|
eventHandler.Append("(sender, e)"); |
|
|
|
eventHandler.AppendLine(); |
|
|
|
eventHandler.AppendLine(); |
|
|
|
eventHandler.Append(indentation); |
|
|
|
eventHandler.Append(indentation); |
|
|
|
eventHandler.Append(textEditorOptions.IndentationString); |
|
|
|
eventHandler.Append(TextEditorOptions.IndentationString); |
|
|
|
eventHandler.Append(body); |
|
|
|
eventHandler.Append(body); |
|
|
|
eventHandler.AppendLine(); |
|
|
|
eventHandler.AppendLine(); |
|
|
|
eventHandler.Append(indentation); |
|
|
|
eventHandler.Append(indentation); |
|
|
@ -245,64 +62,46 @@ namespace ICSharpCode.RubyBinding |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the form or user control class from the compilation unit.
|
|
|
|
/// Insert the event handler at the end of the class with an extra
|
|
|
|
|
|
|
|
/// new line before it.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
IClass GetClass(ICompilationUnit unit) |
|
|
|
public override int InsertEventHandler(IDocument document, string eventHandler) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return unit.Classes[0]; |
|
|
|
IDocumentLine classEndLine = GetClassEndLine(document); |
|
|
|
} |
|
|
|
InsertEventHandlerBeforeLine(document, eventHandler, classEndLine); |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
// Set position so it points to the line
|
|
|
|
/// Gets the start offset of the region.
|
|
|
|
// where the event handler was inserted.
|
|
|
|
/// </summary>
|
|
|
|
return classEndLine.LineNumber; |
|
|
|
static int GetStartOffset(IDocument document, DomRegion region) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return document.PositionToOffset(region.BeginLine, region.BeginColumn); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
IDocumentLine GetClassEndLine(IDocument doc) |
|
|
|
/// Gets the end offset of the region.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
static int GetEndOffset(IDocument document, DomRegion region) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
if (region.EndLine > document.TotalNumberOfLines) { |
|
|
|
int line = doc.TotalNumberOfLines; |
|
|
|
// At end of document.
|
|
|
|
while (line > 0) { |
|
|
|
return document.TextLength; |
|
|
|
IDocumentLine documentLine = doc.GetLine(line); |
|
|
|
|
|
|
|
if (documentLine.Text.Trim() == "end") { |
|
|
|
|
|
|
|
return documentLine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
line--; |
|
|
|
} |
|
|
|
} |
|
|
|
return document.PositionToOffset(region.EndLine, region.EndColumn); |
|
|
|
return doc.GetLine(doc.TotalNumberOfLines); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
void InsertEventHandlerBeforeLine(IDocument doc, string eventHandler, IDocumentLine classEndLine) |
|
|
|
/// Checks if the event handler already exists.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <returns>The line position of the first line of the existing event handler.</returns>
|
|
|
|
|
|
|
|
int GetExistingEventHandler(string methodName) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
ParseInformation parseInfo = ParseFile(); |
|
|
|
string newContent = "\r\n" + eventHandler + "\r\n"; |
|
|
|
IClass c = GetClass(parseInfo.CompilationUnit); |
|
|
|
int offset = classEndLine.Offset; |
|
|
|
foreach (IMethod method in c.Methods) { |
|
|
|
doc.Insert(offset, newContent); |
|
|
|
if ((method.Name == methodName) && (method.Parameters.Count == 2)) { |
|
|
|
|
|
|
|
return method.Region.BeginLine; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Parses the form or user control being designed.
|
|
|
|
/// Converts from the DOM region to a document region.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
ParseInformation ParseFile() |
|
|
|
public override DomRegion GetBodyRegionInDocument(IMethod method) |
|
|
|
{ |
|
|
|
|
|
|
|
return ParseFile(this.ViewContent.DesignerCodeFile.FileName, this.ViewContent.DesignerCodeFileContent); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static string GetProjectRootNamespace(ICompilationUnit compilationUnit) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
IProject project = compilationUnit.ProjectContent.Project as IProject; |
|
|
|
DomRegion bodyRegion = method.BodyRegion; |
|
|
|
if (project != null) { |
|
|
|
return new DomRegion(bodyRegion.BeginLine + 1, 1, bodyRegion.EndLine, 1); |
|
|
|
return project.RootNamespace; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return String.Empty; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|