41
41
using MonoDevelop.Xml.StateEngine;
42
42
using MonoDevelop.Ide.Tasks;
43
43
using MonoDevelop.Ide;
44
using MonoDevelop.Ide.CodeFormatting;
45
46
namespace MonoDevelop.XmlEditor
49
48
public class XmlTextEditorExtension : MonoDevelop.XmlEditor.Gui.BaseXmlEditorExtension
51
50
const string TextXmlMimeType = "text/xml";
72
71
public override void Initialize ()
74
73
base.Initialize ();
75
XmlEditorOptions.XmlSchemaAssociationChanged += HandleXmlSchemaAssociationChanged;
74
XmlEditorOptions.XmlFileAssociationChanged += HandleXmlFileAssociationChanged;
76
75
XmlSchemaManager.UserSchemaAdded += UserSchemaAdded;
77
76
XmlSchemaManager.UserSchemaRemoved += UserSchemaRemoved;
78
77
SetDefaultSchema (FileExtension);
91
void HandleXmlSchemaAssociationChanged (object sender, XmlSchemaAssociationChangedEventArgs e)
90
void HandleXmlFileAssociationChanged (object sender, XmlFileAssociationChangedEventArgs e)
93
92
if (e.Extension == FileExtension)
94
93
SetDefaultSchema (FileExtension);
109
108
#region Code completion
111
// IEditableTextBuffer GetBuffer ()
113
// IEditableTextBuffer buf = Document.GetContent<IEditableTextBuffer> ();
114
// System.Diagnostics.Debug.Assert (buf != null);
118
XmlElementPath GetCurrentPath ()
110
XmlElementPath GetElementPath ()
120
return ConvertPath (Tracker.Engine.Nodes.OfType<XElement> ().Reverse ());
112
return ConvertPath (GetCurrentPath ());
123
static XmlElementPath ConvertPath (IEnumerable<XElement> path)
115
XmlElementPath ConvertPath (IList<XObject> path)
125
XmlElementPath elementPath = new XmlElementPath ();
126
var namespaces = new Dictionary<string, string> ();
127
string defaultNamespace = null;
128
foreach (XElement el in path) {
129
foreach (XAttribute att in el.Attributes) {
130
if (att.Name.HasPrefix) {
131
if (att.Name.Prefix == "xmlns")
132
namespaces [att.Name.Name] = att.Value;
134
if (att.Name.Name == "xmlns")
135
defaultNamespace = att.Value;
117
var elementPath = new XmlElementPath ();
119
if (defaultSchemaCompletionData != null && !string.IsNullOrEmpty (defaultSchemaCompletionData.NamespaceUri))
120
elementPath.Namespaces.AddPrefix (defaultSchemaCompletionData.NamespaceUri, defaultNamespacePrefix ?? "");
122
foreach (var obj in path) {
123
var el = obj as XElement;
126
foreach (var att in el.Attributes) {
127
if (!string.IsNullOrEmpty (att.Value)) {
128
if (att.Name.HasPrefix) {
129
if (att.Name.Prefix == "xmlns")
130
elementPath.Namespaces.AddPrefix (att.Value, att.Name.Name);
131
} else if (att.Name.Name == "xmlns") {
132
elementPath.Namespaces.AddPrefix (att.Value, "");
139
if (el.Name.HasPrefix)
140
namespaces.TryGetValue (el.Name.Prefix, out ns);
142
ns = defaultNamespace;
136
string ns = elementPath.Namespaces.GetNamespace (el.Name.HasPrefix? el.Name.Prefix : "");
143
137
QualifiedName qn = new QualifiedName (el.Name.Name, ns, el.Name.Prefix ?? String.Empty);
144
138
elementPath.Elements.Add (qn);
149
143
protected override void GetElementCompletions (CompletionDataList list)
151
XmlElementPath path = GetCurrentPath ();
145
var path = GetElementPath ();
152
146
if (path.Elements.Count > 0) {
153
147
IXmlCompletionProvider schema = FindSchema (path);
154
148
if (schema == null)
155
149
schema = inferredCompletionData;
156
150
if (schema != null) {
157
CompletionData[] completionData = schema.GetChildElementCompletionData (path);
151
var completionData = schema.GetChildElementCompletionData (path);
158
152
if (completionData != null)
159
153
list.AddRange (completionData);
163
157
} else if (inferredCompletionData != null) {
164
158
list.AddRange (inferredCompletionData.GetElementCompletionData ());
160
AddMiscBeginTags (list);
168
163
protected override CompletionDataList GetAttributeCompletions (IAttributedXObject attributedOb,
169
164
Dictionary<string, string> existingAtts)
171
XmlElementPath path = GetCurrentPath ();
166
var path = GetElementPath ();
172
167
if (path.Elements.Count > 0) {
173
168
IXmlCompletionProvider schema = FindSchema (path);
174
169
if (schema == null)
175
170
schema = inferredCompletionData;
176
if (schema != null) {
177
CompletionData[] completionData = schema.GetAttributeCompletionData (path);
178
if (completionData != null)
179
return new CompletionDataList (completionData);
172
return schema.GetAttributeCompletionData (path);
185
177
protected override CompletionDataList GetAttributeValueCompletions (IAttributedXObject attributedOb, XAttribute att)
187
XmlElementPath path = GetCurrentPath ();
179
var path = GetElementPath ();
188
180
if (path.Elements.Count > 0) {
189
XmlSchemaCompletionData schema = FindSchema (path);
190
if (schema != null) {
191
CompletionData[] completionData = schema.GetAttributeValueCompletionData (path, att.Name.FullName);
192
if (completionData != null)
193
return new CompletionDataList (completionData);
181
var schema = FindSchema (path);
183
return schema.GetAttributeValueCompletionData (path, att.Name.FullName);
253
242
public XmlSchemaObject GetSchemaObjectSelected (XmlSchemaCompletionData currentSchemaCompletionData)
255
244
// Find element under cursor.
256
XmlElementPath path = GetCurrentPath ();
245
XmlElementPath path = GetElementPath ();
258
247
//attribute name under cursor, if valid
259
248
string attributeName = null;
273
262
XmlSchemaElement element = schemaCompletionData.FindElement(path);
274
263
schemaObject = element;
275
264
if (element != null) {
276
if (attributeName.Length > 0) {
265
if (!string.IsNullOrEmpty (attributeName)) {
277
266
XmlSchemaAttribute attribute = schemaCompletionData.FindAttribute(element, attributeName);
278
267
if (attribute != null) {
279
268
if (currentSchemaCompletionData != null) {
487
476
if (TextEditorProperties.IndentStyle == IndentStyle.Smart && key == Gdk.Key.Return) {
488
477
result = base.KeyPress (key, keyChar, modifier);
489
SmartIndentLine (Editor.CursorLine);
478
SmartIndentLine (Editor.Caret.Line);
492
481
return base.KeyPress (key, keyChar, modifier);
524
513
char c = Editor.GetCharAt (i);
525
514
if (c == '\n' || c == '\r')
526
return Editor.GetText (i + 1, indentEnd);
515
return Editor.GetTextBetween (i + 1, indentEnd);
527
516
if (!char.IsWhiteSpace (c))
547
536
//FIXME: implement
550
[CommandHandler (Commands.Format)]
551
public void FormatCommand ()
553
TaskService.Errors.Clear ();
555
using (IProgressMonitor monitor = XmlEditorService.GetMonitor ()) {
556
bool selection = (Editor.SelectionEndPosition - Editor.SelectionStartPosition) > 0;
557
string xml = selection? Editor.SelectedText : Editor.Text;
558
XmlDocument doc = XmlEditorService.ValidateWellFormedness (monitor, xml, FileName);
562
//if there's a line indent at the current location, prepend that to all new lines
563
string extraIndent = null;
565
extraIndent = GetPositionIndent (Editor.SelectionStartPosition);
567
string formattedXml = XmlEditorService.IndentedFormat (xml);
569
//convert newlines and prepend extra indents to each line if needed
570
bool nonNativeNewline = (Editor.NewLine != Environment.NewLine);
571
bool hasExtraIndent = !string.IsNullOrEmpty (extraIndent);
572
if (hasExtraIndent || nonNativeNewline) {
573
System.Text.StringBuilder builder = new System.Text.StringBuilder (formattedXml);
575
if (nonNativeNewline)
576
builder.Replace (Environment.NewLine, Editor.NewLine);
578
if (hasExtraIndent) {
579
builder.Replace (Editor.NewLine, Editor.NewLine + extraIndent);
580
if (formattedXml.EndsWith (Environment.NewLine))
581
builder.Remove (builder.Length - 1 - extraIndent.Length, extraIndent.Length);
583
formattedXml = builder.ToString ();
586
Editor.BeginAtomicUndo ();
588
Editor.SelectedText = formattedXml;
590
Editor.DeleteText (0, Editor.TextLength);
591
Editor.InsertText (0, formattedXml);
593
Editor.EndAtomicUndo ();
597
539
[CommandHandler (Commands.CreateSchema)]
598
540
public void CreateSchemaCommand ()
654
596
IdeApp.Workbench.OpenDocument (
656
598
Math.Max (1, schemaObject.LineNumber),
657
Math.Max (1, schemaObject.LinePosition), true);
599
Math.Max (1, schemaObject.LinePosition));
659
601
} catch (Exception ex) {
660
602
MonoDevelop.Core.LoggingService.LogError ("Could not open document.", ex);
675
[CommandUpdateHandler (CodeFormattingCommands.FormatSelection)]
676
internal void UpdateFormatSelection (CommandInfo info)
678
info.Enabled = false;
681
[CommandHandler (CodeFormattingCommands.FormatSelection)]
682
internal void FormatSelection (CommandInfo info)
684
throw new NotImplementedException ();
688
[CommandUpdateHandler (CodeFormattingCommands.FormatBuffer)]
689
internal void UpdateFormatDocument (CommandInfo info)
691
//we know there is an XML formatter because this addin registers it
695
//we have to implement the command here simply to force the document mimetype
696
//FIXME: instead we should register the XML mimetype additions to the desktopservice
697
[CommandHandler (CodeFormattingCommands.FormatBuffer)]
698
internal void FormatDocument ()
700
var formatter = CodeFormatterService.GetFormatter (TextXmlMimeType);
701
Editor.Document.BeginAtomicUndo ();
702
var loc = Editor.Caret.Location;
703
var text = formatter.FormatText (Document.Project != null ? Document.Project.Policies : null, Editor.Text);
705
Editor.Replace (0, Editor.Length, text);
706
Editor.Caret.Location = loc;
708
Editor.Document.EndAtomicUndo ();
732
711
string GetFileContent (string fileName)
734
713
MonoDevelop.Projects.Text.IEditableTextFile tf =
735
MonoDevelop.DesignerSupport.OpenDocumentFileProvider.Instance.GetEditableTextFile (fileName);
714
MonoDevelop.Ide.TextFileProvider.Instance.GetEditableTextFile (fileName);
738
717
System.IO.StreamReader reader = new System.IO.StreamReader (fileName, true);
739
718
return reader.ReadToEnd();