static public bool OnChar(ScintillaControl Sci, int Value, int position, int style) { if (style == 3 || style == 124) { switch (Value) { // documentation tag case '@': return HandleDocTagCompletion(Sci); // documentation bloc case '*': if ((position > 2) && (Sci.CharAt(position-3) == '/') && (Sci.CharAt(position-2) == '*') && ((position == 3) || (Sci.BaseStyleAt(position-4) != 3))) HandleBoxCompletion(Sci, position); break; } } return false; }
private void OnUpdateCallTip(ScintillaControl sci, int position) { if (ASComplete.HasCalltip()) { int pos = sci.CurrentPos - 1; char c = (char)sci.CharAt(pos); if ((c == ',' || c == '(') && sci.BaseStyleAt(pos) == 0) sci.Colourise(0, -1); ASComplete.HandleFunctionCompletion(sci, false, true); } }
private void OnMouseHover(ScintillaControl sci, int position) { if (!ASContext.Context.IsFileValid) return; lastHoverPosition = position; // get word at mouse position int style = sci.BaseStyleAt(position); if (!ASComplete.IsTextStyle(style)) return; position = sci.WordEndPosition(position, true); ASResult result = ASComplete.GetExpressionType(sci, position); // set tooltip if (!result.IsNull()) { string text = ASComplete.GetToolTipText(result); if (text == null) return; // show tooltip UITools.Tip.ShowAtMouseLocation(text); } }
public static void ContextualGenerator(ScintillaControl Sci, List<ICompletionListItem> options) { if (ASContext.Context is ASContext) (ASContext.Context as ASContext).UpdateCurrentFile(false); // update model if ((ASContext.Context.CurrentClass.Flags & (FlagType.Enum | FlagType.TypeDef)) > 0) return; lookupPosition = -1; int position = Sci.CurrentPos; int style = Sci.BaseStyleAt(position); if (style == 19) // on keyword return; bool isNotInterface = (ASContext.Context.CurrentClass.Flags & FlagType.Interface) == 0; int line = Sci.LineFromPosition(position); contextToken = Sci.GetWordFromPosition(position); contextMatch = null; FoundDeclaration found = GetDeclarationAtLine(Sci, line); string text = Sci.GetLine(line); bool suggestItemDeclaration = false; if (isNotInterface && ASComplete.IsLiteralStyle(style)) { ShowConvertToConst(found, options); return; } ASResult resolve = ASComplete.GetExpressionType(Sci, Sci.WordEndPosition(position, true)); contextResolved = resolve; // ignore automatic vars (MovieClip members) if (isNotInterface && resolve.Member != null && (((resolve.Member.Flags & FlagType.AutomaticVar) > 0) || (resolve.InClass != null && resolve.InClass.QualifiedName == "Object"))) { resolve.Member = null; resolve.Type = null; } if (isNotInterface && found.inClass != ClassModel.VoidClass && contextToken != null) { if (resolve.Member == null && resolve.Type != null && (resolve.Type.Flags & FlagType.Interface) > 0) // implement interface { contextParam = resolve.Type.Type; ShowImplementInterface(found, options); return; } if (resolve.Member != null && !ASContext.Context.CurrentClass.IsVoid() && (resolve.Member.Flags & FlagType.LocalVar) > 0) // promote to class var { contextMember = resolve.Member; ShowPromoteLocalAndAddParameter(found, options); return; } } if (contextToken != null && resolve.Member == null) // import declaration { if ((resolve.Type == null || resolve.Type.IsVoid() || !ASContext.Context.IsImported(resolve.Type, line)) && CheckAutoImport(found, options)) return; if (resolve.Type == null) { suggestItemDeclaration = ASComplete.IsTextStyle(Sci.BaseStyleAt(position - 1)); } } if (isNotInterface && found.member != null) { // private var -> property if ((found.member.Flags & FlagType.Variable) > 0 && (found.member.Flags & FlagType.LocalVar) == 0) { // maybe we just want to import the member's non-imported type Match m = Regex.Match(text, String.Format(patternVarDecl, found.member.Name, contextToken)); if (m.Success) { contextMatch = m; ClassModel type = ASContext.Context.ResolveType(contextToken, ASContext.Context.CurrentModel); if (type.IsVoid() && CheckAutoImport(found, options)) return; } ShowGetSetList(found, options); return; } // inside a function else if ((found.member.Flags & (FlagType.Function | FlagType.Getter | FlagType.Setter)) > 0 && resolve.Member == null && resolve.Type == null) { if (contextToken != null) { // "generate event handlers" suggestion string re = String.Format(patternEvent, contextToken); Match m = Regex.Match(text, re, RegexOptions.IgnoreCase); if (m.Success) { contextMatch = m; contextParam = CheckEventType(m.Groups["event"].Value); ShowEventList(found, options); return; } m = Regex.Match(text, String.Format(patternAS2Delegate, contextToken), RegexOptions.IgnoreCase); if (m.Success) { contextMatch = m; ShowDelegateList(found, options); return; } // suggest delegate if (ASContext.Context.Features.hasDelegates) { m = Regex.Match(text, @"([a-z0-9_.]+)\s*\+=\s*" + contextToken, RegexOptions.IgnoreCase); if (m.Success) { int offset = Sci.PositionFromLine(Sci.LineFromPosition(position)) + m.Groups[1].Index + m.Groups[1].Length; resolve = ASComplete.GetExpressionType(Sci, offset); if (resolve.Member != null) contextMember = ResolveDelegate(resolve.Member.Type, resolve.InFile); contextMatch = m; ShowDelegateList(found, options); return; } } } else { // insert a default handler name, then "generate event handlers" suggestion Match m = Regex.Match(text, String.Format(patternEvent, ""), RegexOptions.IgnoreCase); if (m.Success) { int regexIndex = m.Index + Sci.PositionFromLine(Sci.CurrentLine); GenerateDefaultHandlerName(Sci, position, regexIndex, m.Groups["event"].Value, true); resolve = ASComplete.GetExpressionType(Sci, Sci.CurrentPos); if (resolve.Member == null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0) { contextMatch = m; contextParam = CheckEventType(m.Groups["event"].Value); ShowEventList(found, options); } return; } // insert default delegate name, then "generate delegate" suggestion if (ASContext.Context.Features.hasDelegates) { m = Regex.Match(text, @"([a-z0-9_.]+)\s*\+=\s*", RegexOptions.IgnoreCase); if (m.Success) { int offset = Sci.PositionFromLine(Sci.LineFromPosition(position)) + m.Groups[1].Index + m.Groups[1].Length; resolve = ASComplete.GetExpressionType(Sci, offset); if (resolve.Member != null) { contextMember = ResolveDelegate(resolve.Member.Type, resolve.InFile); string delegateName = resolve.Member.Name; if (delegateName.StartsWithOrdinal("on")) delegateName = delegateName.Substring(2); GenerateDefaultHandlerName(Sci, position, offset, delegateName, false); resolve = ASComplete.GetExpressionType(Sci, Sci.CurrentPos); if (resolve.Member == null || (resolve.Member.Flags & FlagType.AutomaticVar) > 0) { contextMatch = m; ShowDelegateList(found, options); } return; } } } } } // "Generate fields from parameters" suggestion if (found.member != null && (found.member.Flags & FlagType.Function) > 0 && found.member.Parameters != null && (found.member.Parameters.Count > 0) && resolve.Member != null && (resolve.Member.Flags & FlagType.ParameterVar) > 0) { contextMember = resolve.Member; ShowFieldFromParameter(found, options); return; } // "add to interface" suggestion if (resolve.Member != null && resolve.Member.Name == found.member.Name && line == found.member.LineFrom && ((found.member.Flags & FlagType.Function) > 0 || (found.member.Flags & FlagType.Getter) > 0 || (found.member.Flags & FlagType.Setter) > 0) && found.inClass != ClassModel.VoidClass && found.inClass.Implements != null && found.inClass.Implements.Count > 0) { string funcName = found.member.Name; FlagType flags = found.member.Flags & ~FlagType.Access; List<string> interfaces = new List<string>(); foreach (string interf in found.inClass.Implements) { bool skip = false; ClassModel cm = ASContext.Context.ResolveType(interf, ASContext.Context.CurrentModel); foreach (MemberModel m in cm.Members) { if (m.Name.Equals(funcName) && m.Flags.Equals(flags)) { skip = true; break; } } if (!skip) { interfaces.Add(interf); } } if (interfaces.Count > 0) { ShowAddInterfaceDefList(found, interfaces, options); return; } } // "assign var to statement" suggestion int curLine = Sci.CurrentLine; string ln = Sci.GetLine(curLine).TrimEnd(); if (ln.Length > 0 && ln.IndexOf('=') == -1 && ln.Length <= Sci.CurrentPos - Sci.PositionFromLine(curLine)) // cursor at end of line { ShowAssignStatementToVarList(found, options); return; } } // suggest generate constructor / toString if (isNotInterface && found.member == null && found.inClass != ClassModel.VoidClass && contextToken == null) { bool hasConstructor = false; bool hasToString = false; foreach (MemberModel m in ASContext.Context.CurrentClass.Members) { if (!hasConstructor && (m.Flags & FlagType.Constructor) > 0) hasConstructor = true; if (!hasToString && (m.Flags & FlagType.Function) > 0 && m.Name.Equals("toString")) hasToString = true; } if (!hasConstructor || !hasToString) { ShowConstructorAndToStringList(found, hasConstructor, hasToString, options); return; } } if (isNotInterface && resolve.Member != null && resolve.Type != null && resolve.Type.QualifiedName == ASContext.Context.Features.stringKey && found.inClass != ClassModel.VoidClass) { int lineStartPos = Sci.PositionFromLine(Sci.CurrentLine); string lineStart = text.Substring(0, Sci.CurrentPos - lineStartPos); Match m = Regex.Match(lineStart, String.Format(@"new\s+(?<event>\w+)\s*\(\s*\w+", lineStart)); if (m.Success) { Group g = m.Groups["event"]; ASResult eventResolve = ASComplete.GetExpressionType(Sci, lineStartPos + g.Index + g.Length); if (eventResolve != null && eventResolve.Type != null) { ClassModel aType = eventResolve.Type; aType.ResolveExtends(); while (!aType.IsVoid() && aType.QualifiedName != "Object") { if (aType.QualifiedName == "flash.events.Event") { contextParam = eventResolve.Type.QualifiedName; ShowEventMetatagList(found, options); return; } aType = aType.Extends; } } } } // suggest declaration if (contextToken != null) { if (suggestItemDeclaration) { Match m = Regex.Match(text, String.Format(patternClass, contextToken)); if (m.Success) { contextMatch = m; ShowNewClassList(found, options); } else if (!found.inClass.IsVoid()) { m = Regex.Match(text, String.Format(patternMethod, contextToken)); if (m.Success) { contextMatch = m; ShowNewMethodList(found, options); } else ShowNewVarList(found, options); } } else { if (resolve != null && resolve.InClass != null && resolve.InClass.InFile != null && resolve.Member != null && (resolve.Member.Flags & FlagType.Function) > 0 && File.Exists(resolve.InClass.InFile.FileName) && !resolve.InClass.InFile.FileName.StartsWithOrdinal(PathHelper.AppDir)) { Match m = Regex.Match(text, String.Format(patternMethodDecl, contextToken)); Match m2 = Regex.Match(text, String.Format(patternMethod, contextToken)); if (!m.Success && m2.Success) { contextMatch = m; ShowChangeMethodDeclList(found, options); } } else if (resolve != null && resolve.Type != null && resolve.Type.InFile != null && resolve.RelClass != null && File.Exists(resolve.Type.InFile.FileName) && !resolve.Type.InFile.FileName.StartsWithOrdinal(PathHelper.AppDir)) { Match m = Regex.Match(text, String.Format(patternClass, contextToken)); if (m.Success) { contextMatch = m; ShowChangeConstructorDeclList(found, options); } } } } // TODO: Empty line, show generators list? yep }
private static void ConvertToConst(ClassModel inClass, ScintillaControl sci, MemberModel member, bool detach) { String suggestion = "NEW_CONST"; String label = TextHelper.GetString("ASCompletion.Label.ConstName"); String title = TextHelper.GetString("ASCompletion.Title.ConvertToConst"); Hashtable info = new Hashtable(); info["suggestion"] = suggestion; info["label"] = label; info["title"] = title; DataEvent de = new DataEvent(EventType.Command, "ProjectManager.LineEntryDialog", info); EventManager.DispatchEvent(null, de); if (!de.Handled) return; suggestion = (string)info["suggestion"]; int position = sci.CurrentPos; int style = sci.BaseStyleAt(position); MemberModel latest = null; int wordPosEnd = position + 1; int wordPosStart = position; while (sci.BaseStyleAt(wordPosEnd) == style) wordPosEnd++; while (sci.BaseStyleAt(wordPosStart - 1) == style) wordPosStart--; sci.SetSel(wordPosStart, wordPosEnd); string word = sci.SelText; sci.ReplaceSel(suggestion); if (member == null) { detach = false; lookupPosition = -1; position = sci.WordStartPosition(sci.CurrentPos, true); sci.SetSel(position, sci.WordEndPosition(position, true)); } else { latest = GetLatestMemberForVariable(GeneratorJobType.Constant, inClass, Visibility.Private, new MemberModel("", "", FlagType.Static, 0)); if (latest != null) { position = FindNewVarPosition(sci, inClass, latest); } else { position = GetBodyStart(inClass.LineFrom, inClass.LineTo, sci); detach = false; } if (position <= 0) return; sci.SetSel(position, position); } MemberModel m = NewMember(suggestion, member, FlagType.Variable | FlagType.Constant | FlagType.Static, GetDefaultVisibility(inClass)); var features = ASContext.Context.Features; switch (style) { case 4: m.Type = features.numberKey; break; case 6: case 7: m.Type = features.stringKey; break; } m.Value = word; GenerateVariable(m, position, detach); }
/// <summary> /// Tries to get the start position of a code block, delimited by { and } /// </summary> /// <param name="lineFrom">The line inside the Scintilla document where the owner member of the body starts</param> /// <param name="lineTo">The line inside the Scintilla document where the owner member of the body ends</param> /// <param name="sci">The Scintilla control containing the document</param> /// <param name="needsPointOfInsertion">If true looks for the position to add new code, inserting new lines if needed</param> /// <returns>The position inside the Scintilla document, or -1 if not suitable position was found</returns> public static int GetBodyStart(int lineFrom, int lineTo, ScintillaControl sci, bool needsPointOfInsertion) { int posStart = sci.PositionFromLine(lineFrom); int posEnd = sci.LineEndPosition(lineTo); int funcBodyStart = -1; int genCount = 0; for (int i = posStart; i <= posEnd; i++) { char c = (char)sci.CharAt(i); if (c == '{') { int style = sci.BaseStyleAt(i); if (ASComplete.IsCommentStyle(style) || ASComplete.IsLiteralStyle(style) || genCount > 0) continue; funcBodyStart = i; break; } else if (c == '<') { int style = sci.BaseStyleAt(i); if (style == 10) genCount++; } else if (c == '>') { int style = sci.BaseStyleAt(i); if (style == 10) genCount--; } } if (funcBodyStart == -1) return -1; if (needsPointOfInsertion) { int ln = sci.LineFromPosition(funcBodyStart); funcBodyStart++; return GetOrSetPointOfInsertion(funcBodyStart, posEnd, ln, sci); } return funcBodyStart + 1; }
/// <summary> /// Gets the xml context tag /// </summary> public static XMLContextTag GetXMLContextTag(ScintillaControl sci, Int32 position) { XMLContextTag xtag = new XMLContextTag(); if ((position == 0) || (sci == null)) return xtag; string tag = ""; //Char c = (Char)sci.CharAt(position); //tag += c; position--; Char c = (Char)sci.CharAt(position); tag = c + tag; bool inComment = false; bool inCDATA = false; while (position > 0) { position--; c = (Char)sci.CharAt(position); tag = c + tag; if (tag == "]]>") inCDATA = true; else if (tag == "-->") inComment = true; if (c == '<') { if ((inComment && !tag.StartsWith("<!--")) || (inCDATA && !tag.StartsWith("<![CDATA["))) continue; break; } if (inCDATA || inComment) continue; if (c == '>') { xtag.Position = position + 1; return xtag; } else if (c == '{' && sci.BaseStyleAt(position) != 6 /*XML attribute value*/) { // code probably not inside a tag: most likely style or script tag without CDATA or comment return xtag; } } xtag.Position = position; xtag.Tag = tag; Match mTag = tagName.Match(tag + " "); if (mTag.Success) { xtag.Name = mTag.Groups["name"].Value; xtag.Closing = tag[1] == '/'; xtag.Closed = tag.EndsWith("/>") || tag.EndsWith("-->"); if (xtag.Name.IndexOf(':') > 0) { xtag.NameSpace = xtag.Name.Substring(0, xtag.Name.IndexOf(':')); } } else if (tag.StartsWith("<!--")) { xtag.Name = "!--"; xtag.Closed = tag.EndsWith("-->"); } else if (tag.StartsWith("<![CDATA[")) { xtag.Name = "![CDATA["; xtag.Closed = tag.EndsWith("]]>"); } return xtag; }
/// <summary> /// Checks if a line is in preprocessor block /// </summary> public bool LineIsInPreprocessor(ScintillaControl sci, int lexerPpStyle, int line) { bool ppEnd = false; bool ppStart = false; int foldHeader = (int)ScintillaNet.Enums.FoldLevel.HeaderFlag; for (var i = line; i > 0; i--) { int pos = sci.PositionFromLine(i); int ind = sci.GetLineIndentation(i); int style = sci.BaseStyleAt(pos + ind); if (style == lexerPpStyle) { int fold = sci.GetFoldLevel(i) & foldHeader; if (fold == foldHeader) ppStart = true; break; } } for (var i = line; i < sci.LineCount; i++) { int pos = sci.PositionFromLine(i); int ind = sci.GetLineIndentation(i); int style = sci.BaseStyleAt(pos + ind); if (style == lexerPpStyle) { int fold = sci.GetFoldLevel(i) & foldHeader; if (fold != foldHeader) ppEnd = true; break; } } if (ppStart && ppEnd) return true; else return false; }
/// <summary> /// Handles the incoming character /// </summary> public static void OnChar(ScintillaControl sci, Int32 value) { if (cType == XMLType.Invalid || (sci.ConfigurationLanguage != "xml" && sci.ConfigurationLanguage != "html")) return; XMLContextTag ctag; Int32 position = sci.CurrentPos; if (sci.BaseStyleAt(position) == 6 && value != '"') return; // in XML attribute Char c = ' '; DataEvent de; switch (value) { case 10: // Shift+Enter to insert <BR/> Int32 line = sci.LineFromPosition(position); if (Control.ModifierKeys == Keys.Shift) { ctag = GetXMLContextTag(sci, position); if (ctag.Tag == null || ctag.Tag.EndsWith(">")) { int start = sci.PositionFromLine(line)-((sci.EOLMode == 0)? 2:1); sci.SetSel(start, position); sci.ReplaceSel((PluginSettings.UpperCaseHtmlTags) ? "<BR/>" : "<br/>"); sci.SetSel(start+5, start+5); return; } } if (PluginSettings.SmartIndenter) { // There is no standard for XML formatting, although most IDEs have similarities. We are mostly going with Visual Studio style with slight differences. // Get last non-empty line. String text = ""; Int32 line2 = line - 1; while (line2 >= 0 && text.Length == 0) { text = sci.GetLine(line2).TrimEnd(); line2--; } if ((text.EndsWith(">") && !text.EndsWith("?>") && !text.EndsWith("%>")) || text.EndsWith("<!--") || text.EndsWith("<![CDATA[")) { // Get the previous tag. do { position--; c = (Char)sci.CharAt(position); } while (position > 0 && c != '>'); ctag = GetXMLContextTag(sci, c == '>' ? position + 1 : position); // Line indentation. Int32 indent = sci.GetLineIndentation(line2 + 1); String checkStart = null; bool subIndent = true; if (text.EndsWith("<!--")) { checkStart = "-->"; subIndent = false; } else if (text.EndsWith("<![CDATA[")) { checkStart = "]]>"; subIndent = false; } else if (ctag.Closed || ctag.Closing) { //Closed tag. Look for the nearest open and not closed tag for proper indentation subIndent = false; if (ctag.Name != null) { var tmpTags = new Stack<XMLContextTag>(); var tmpTag = ctag; if (!tmpTag.Closed) tmpTags.Push(tmpTag); while (tmpTag.Position != 0) { tmpTag = GetXMLContextTag(sci, tmpTag.Position); if (tmpTag.Tag != null && tmpTag.Name != null) { if (tmpTag.Closed) continue; else if (tmpTag.Closing) { tmpTags.Push(tmpTag); } else { if (tmpTags.Count > 0 && tmpTags.Peek().Name == tmpTag.Name) tmpTags.Pop(); else break; } } } if (tmpTags.Count > 0) indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTags.Pop().Position)); else if (tmpTag.Name != null) { subIndent = true; checkStart = "</" + tmpTag.Name; indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTag.Position)); } else { indent = sci.GetLineIndentation(sci.LineFromPosition(tmpTag.Position)); } } } else if (ctag.Name != null) { // Indentation. Some IDEs use the tag position, VS uses the tag start line indentation. indent = sci.GetLineIndentation(sci.LineFromPosition(ctag.Position)); checkStart = "</" + ctag.Name; if (ctag.Name.ToLower() == "script" || ctag.Name.ToLower() == "style") subIndent = false; } try { sci.BeginUndoAction(); if (checkStart != null) { text = sci.GetLine(line).TrimStart(); if (text.StartsWith(checkStart)) { sci.SetLineIndentation(line, indent); sci.InsertText(sci.PositionFromLine(line), LineEndDetector.GetNewLineMarker(sci.EOLMode)); } } // Indent the code if (subIndent) indent += sci.Indent; sci.SetLineIndentation(line, indent); position = sci.LineIndentPosition(line); sci.SetSel(position, position); } finally { sci.EndUndoAction(); } return; } else if (!text.EndsWith(">")) { ctag = GetXMLContextTag(sci, sci.CurrentPos); if (ctag.Tag == null || ctag.Name == null) return; // We're inside a tag. Visual Studio indents with regards to the first line, other IDEs indent using the indentation of the last line with text. int indent; string tag = (ctag.Tag.IndexOf('\r') > 0 || ctag.Tag.IndexOf('\n') > 0) ? ctag.Tag.Substring(0, ctag.Tag.IndexOfAny(new[] {'\r', '\n'})).TrimEnd() : ctag.Tag.TrimEnd(); if (tag.EndsWith("\"")) { int i; int l = tag.Length; for (i = ctag.Name.Length + 1; i < l; i++) { if (!char.IsWhiteSpace(tag[i])) break; } indent = sci.Column(ctag.Position) + sci.MBSafePosition(i); } else { indent = sci.GetLineIndentation(sci.LineFromPosition(ctag.Position)) + sci.Indent; } sci.SetLineIndentation(line, indent); position = sci.LineIndentPosition(line); sci.SetSel(position, position); return; } } break; case '<': case '/': if (value == '/') { if ((position < 2) || ((Char)sci.CharAt(position-2) != '<')) return; ctag = new XMLContextTag(); ctag.Position = position - 2; ctag.Closing = true; } else { ctag = GetXMLContextTag(sci, position); if (ctag.Tag != null) return; } // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.Element", ctag); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; // New tag if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known) { List<ICompletionListItem> items = new List<ICompletionListItem>(); String previous = null; foreach (string ns in namespaces) { items.Add(new NamespaceItem(ns)); } foreach (HTMLTag tag in knownTags) if (tag.Name != previous && (tag.NS == "" || tag.NS == defaultNS)) { items.Add( new HtmlTagItem(tag.Name, tag.Tag)); previous = tag.Name; } items.Sort(new ListItemComparer()); CompletionList.Show(items, true); } return; case ':': ctag = GetXMLContextTag(sci, position); if (ctag.NameSpace == null || position - ctag.Position > ctag.Name.Length + 2) return; // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.Namespace", ctag); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; // Show namespace's tags if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known) { List<ICompletionListItem> items = new List<ICompletionListItem>(); String previous = null; foreach (HTMLTag tag in knownTags) if (tag.Name != previous && tag.NS == ctag.NameSpace) { items.Add(new HtmlTagItem(tag.Name, tag.Name)); previous = tag.Name; } CompletionList.Show(items, true); } return; case '>': if (PluginSettings.CloseTags) { ctag = GetXMLContextTag(sci, position); if (ctag.Name != null && !ctag.Closed) { // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.CloseElement", ctag); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; if (ctag.Closing) return; Boolean isLeaf = false; if (cType == XMLType.Known) foreach(HTMLTag tag in knownTags) { if (String.Compare(tag.Tag, ctag.Name, true) == 0) { isLeaf = tag.IsLeaf; break; } } if (isLeaf) { sci.SetSel(position-1,position); sci.ReplaceSel("/>"); sci.SetSel(position+1, position+1); } else { String closeTag = "</"+ctag.Name+">"; sci.ReplaceSel(closeTag); sci.SetSel(position, position); } } } return; case ' ': c = (char)sci.CharAt(position); if (c > 32 && c != '/' && c != '>' && c != '<') return; ctag = GetXMLContextTag(sci, position); if (ctag.Tag != null) { if (InQuotes(ctag.Tag) || ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('=')) return; // Allow another plugin to handle this Object[] obj = new Object[] { ctag, "" }; de = new DataEvent(EventType.Command, "XMLCompletion.Attribute", obj); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known) { foreach (HTMLTag tag in knownTags) if (String.Compare(tag.Tag, ctag.Name, true) == 0) { List<ICompletionListItem> items = new List<ICompletionListItem>(); String previous = null; foreach (String attr in tag.Attributes) if (attr != previous) { items.Add(new HtmlAttributeItem(attr)); previous = attr; } CompletionList.Show(items, true); return; } } } /*else { if (Control.ModifierKeys == Keys.Shift) { sci.SetSel(position - 1, position); sci.ReplaceSel(" "); } }*/ return; case '=': if (PluginSettings.InsertQuotes) { ctag = GetXMLContextTag(sci, position); position = sci.CurrentPos-2; if (ctag.Tag != null && !String.IsNullOrEmpty(ctag.Name) && Char.IsLetter(ctag.Name[0]) && !InQuotes(ctag.Tag) && (GetWordLeft(sci, ref position).Length > 0)) { position = sci.CurrentPos; c = (Char)sci.CharAt(position); if (c > 32 && c != '>') sci.ReplaceSel("\"\" "); else sci.ReplaceSel("\"\""); sci.SetSel(position+1, position+1); justInsertedQuotesAt = position+1; // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] { ctag, string.Empty }); EventManager.DispatchEvent(PluginBase.MainForm, de); } } return; case '"': ctag = GetXMLContextTag(sci, position); if (position > 1 && ctag.Tag != null && !ctag.Tag.StartsWith("<!")) { // TODO Colorize text change to highlight what's been done if (justInsertedQuotesAt == position - 1) { justInsertedQuotesAt = -1; c = (Char)sci.CharAt(position - 2); if (c == '"' && (Char)sci.CharAt(position-2) == '"') { sci.SetSel(position - 2, position); sci.ReplaceSel("\""); } // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new Object[] {ctag, string.Empty}); EventManager.DispatchEvent(PluginBase.MainForm, de); } else { c = (Char)sci.CharAt(position - 1); if (c == '"' && (Char)sci.CharAt(position) == '"') { sci.SetSel(position - 1, position + 1); sci.ReplaceSel("\""); } } } break; case '?': case '%': if (PluginSettings.CloseTags && position > 1) { ctag = GetXMLContextTag(sci, position-2); if (ctag.Tag == null || ctag.Tag.EndsWith(">")) { if ((Char)sci.CharAt(position-2) == '<') { sci.ReplaceSel((Char)value + ">"); sci.SetSel(position, position); } } } break; case '!': if (PluginSettings.CloseTags && position > 1) { ctag = GetXMLContextTag(sci, position-2); if (ctag.Tag == null || ctag.Tag.EndsWith(">")) { if ((Char)sci.CharAt(position-2) == '<') { CompletionList.Show(xmlBlocks, true); } } } break; } }
/// <summary> /// Add closing brace to a code block. /// If enabled, move the starting brace to a new line. /// </summary> /// <param name="Sci"></param> /// <param name="txt"></param> /// <param name="line"></param> public static void AutoCloseBrace(ScintillaControl Sci, int line) { // find matching brace int bracePos = Sci.LineEndPosition(line - 1) - 1; while ((bracePos > 0) && (Sci.CharAt(bracePos) != '{')) bracePos--; if (bracePos == 0 || Sci.BaseStyleAt(bracePos) != 5) return; int match = Sci.SafeBraceMatch(bracePos); int start = line; int indent = Sci.GetLineIndentation(start - 1); if (match > 0) { int endIndent = Sci.GetLineIndentation(Sci.LineFromPosition(match)); if (endIndent + Sci.TabWidth > indent) return; } // find where to include the closing brace int startIndent = indent; int count = Sci.LineCount; int lastLine = line; int position; string txt = Sci.GetLine(line).Trim(); line++; int eolMode = Sci.EOLMode; string NL = LineEndDetector.GetNewLineMarker(eolMode); if (txt.Length > 0 && ")]};,".IndexOf(txt[0]) >= 0) { Sci.BeginUndoAction(); try { position = Sci.CurrentPos; Sci.InsertText(position, NL + "}"); Sci.SetLineIndentation(line, startIndent); } finally { Sci.EndUndoAction(); } return; } else { while (line < count - 1) { txt = Sci.GetLine(line).TrimEnd(); if (txt.Length != 0) { indent = Sci.GetLineIndentation(line); if (indent <= startIndent) break; lastLine = line; } else break; line++; } } if (line >= count - 1) lastLine = start; // insert closing brace Sci.BeginUndoAction(); try { position = Sci.LineEndPosition(lastLine); Sci.InsertText(position, NL + "}"); Sci.SetLineIndentation(lastLine + 1, startIndent); } finally { Sci.EndUndoAction(); } }
public static bool IsInsideCommentOrString(SearchMatch match, ScintillaControl sci, bool includeComments, bool includeStrings) { int style = sci.BaseStyleAt(match.Index); return includeComments && IsCommentStyle(style) || includeStrings && IsStringStyle(style); }
/// <summary> /// Handles the incoming character /// </summary> public static void OnChar(ScintillaControl sci, Int32 value) { if (cType == XMLType.Invalid || (sci.ConfigurationLanguage != "xml" && sci.ConfigurationLanguage != "html")) return; XMLContextTag ctag; Int32 position = sci.CurrentPos; if (sci.BaseStyleAt(position) == 6 && value != '"') return; // in XML attribute Char c = ' '; DataEvent de; switch (value) { case 10: // Shift+Enter to insert <BR/> Int32 line = sci.LineFromPosition(position); if (Control.ModifierKeys == Keys.Shift) { ctag = GetXMLContextTag(sci, position); if (ctag.Tag == null || ctag.Tag.EndsWith(">")) { int start = sci.PositionFromLine(line)-((sci.EOLMode == 0)? 2:1); sci.SetSel(start, position); sci.ReplaceSel((PluginSettings.UpperCaseHtmlTags) ? "<BR/>" : "<br/>"); sci.SetSel(start+5, start+5); return; } } if (PluginSettings.SmartIndenter) { // Get last non-empty line String text = ""; Int32 line2 = line - 1; while (line2 >= 0 && text.Length == 0) { text = sci.GetLine(line2).TrimEnd(); line2--; } if ((text.EndsWith(">") && !text.EndsWith("?>") && !text.EndsWith("%>") && !closingTag.IsMatch(text)) || text.EndsWith("<!--") || text.EndsWith("<![CDATA[")) { // Get the previous tag do { position--; c = (Char)sci.CharAt(position); } while (position > 0 && c != '>'); ctag = GetXMLContextTag(sci, c == '>' ? position + 1 : position); if ((Char)sci.CharAt(position-1) == '/') return; // Insert blank line if we pressed Enter between a tag & it's closing tag Int32 indent = sci.GetLineIndentation(line2 + 1); String checkStart = null; bool subIndent = true; if (text.EndsWith("<!--")) { checkStart = "-->"; subIndent = false; } else if (text.EndsWith("<![CDATA[")) { checkStart = "]]>"; subIndent = false; } else if (ctag.Closed) subIndent = false; else if (ctag.Name != null) { checkStart = "</" + ctag.Name; if (ctag.Name.ToLower() == "script" || ctag.Name.ToLower() == "style") subIndent = false; if (ctag.Tag.IndexOf('\r') > 0 || ctag.Tag.IndexOf('\n') > 0) subIndent = false; } if (checkStart != null) { text = sci.GetLine(line).TrimStart(); if (text.StartsWith(checkStart)) { sci.SetLineIndentation(line, indent); sci.InsertText(sci.PositionFromLine(line), LineEndDetector.GetNewLineMarker(sci.EOLMode)); } } // Indent the code if (subIndent) indent += sci.Indent; sci.SetLineIndentation(line, indent); position = sci.LineIndentPosition(line); sci.SetSel(position, position); return; } } break; case '<': case '/': if (value == '/') { if ((position < 2) || ((Char)sci.CharAt(position-2) != '<')) return; ctag = new XMLContextTag(); ctag.Closing = true; } else { ctag = GetXMLContextTag(sci, position); if (ctag.Tag != null) return; } // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.Element", ctag); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; // New tag if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known) { List<ICompletionListItem> items = new List<ICompletionListItem>(); String previous = null; foreach (string ns in namespaces) { items.Add(new NamespaceItem(ns)); } foreach (HTMLTag tag in knownTags) if (tag.Name != previous && (tag.NS == "" || tag.NS == defaultNS)) { items.Add( new HtmlTagItem(tag.Name, tag.Tag)); previous = tag.Name; } items.Sort(new ListItemComparer()); CompletionList.Show(items, true); } return; case ':': ctag = GetXMLContextTag(sci, position); if (ctag.NameSpace == null || position - ctag.Position > ctag.Name.Length + 2) return; // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.Namespace", ctag); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; // Show namespace's tags if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known) { List<ICompletionListItem> items = new List<ICompletionListItem>(); String previous = null; foreach (HTMLTag tag in knownTags) if (tag.Name != previous && tag.NS == ctag.NameSpace) { items.Add(new HtmlTagItem(tag.Name, tag.Name)); previous = tag.Name; } CompletionList.Show(items, true); } return; case '>': if (PluginSettings.CloseTags) { ctag = GetXMLContextTag(sci, position); if (ctag.Name != null && !ctag.Closed) { // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.CloseElement", ctag); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; if (ctag.Closing) return; Boolean isLeaf = false; if (cType == XMLType.Known) foreach(HTMLTag tag in knownTags) { if (String.Compare(tag.Tag, ctag.Name, true) == 0) { isLeaf = tag.IsLeaf; break; } } if (isLeaf) { sci.SetSel(position-1,position); sci.ReplaceSel("/>"); sci.SetSel(position+1, position+1); } else { String closeTag = "</"+ctag.Name+">"; sci.ReplaceSel(closeTag); sci.SetSel(position, position); } } } return; case ' ': c = (char)sci.CharAt(position); if (c > 32 && c != '/' && c != '>' && c != '<') return; ctag = GetXMLContextTag(sci, position); if (ctag.Tag != null) { if (InQuotes(ctag.Tag) || ctag.Tag.LastIndexOf('"') < ctag.Tag.LastIndexOf('=')) return; // Allow another plugin to handle this Object[] obj = new Object[] { ctag, "" }; de = new DataEvent(EventType.Command, "XMLCompletion.Attribute", obj); EventManager.DispatchEvent(PluginBase.MainForm, de); if (de.Handled) return; if (PluginSettings.EnableXMLCompletion && cType == XMLType.Known) { foreach (HTMLTag tag in knownTags) if (String.Compare(tag.Tag, ctag.Name, true) == 0) { List<ICompletionListItem> items = new List<ICompletionListItem>(); String previous = null; foreach (String attr in tag.Attributes) if (attr != previous) { items.Add(new HtmlAttributeItem(attr)); previous = attr; } CompletionList.Show(items, true); return; } } } /*else { if (Control.ModifierKeys == Keys.Shift) { sci.SetSel(position - 1, position); sci.ReplaceSel(" "); } }*/ return; case '=': if (PluginSettings.InsertQuotes) { ctag = GetXMLContextTag(sci, position); position = sci.CurrentPos-2; if (ctag.Tag != null && !ctag.Tag.StartsWith("<!") && !InQuotes(ctag.Tag) && (GetWordLeft(sci, ref position).Length > 0)) { position = sci.CurrentPos; c = (Char)sci.CharAt(position); if (c > 32 && c != '>') sci.ReplaceSel("\"\" "); else sci.ReplaceSel("\"\""); sci.SetSel(position+1, position+1); justInsertedQuotesAt = position+1; // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new XMLContextTag()); EventManager.DispatchEvent(PluginBase.MainForm, de); } } return; case '"': ctag = GetXMLContextTag(sci, position); if (position > 1 && ctag.Tag != null && !ctag.Tag.StartsWith("<!")) { // TODO Colorize text change to highlight what's been done if (justInsertedQuotesAt == position - 1) { justInsertedQuotesAt = -1; c = (Char)sci.CharAt(position - 2); if (c == '"' && (Char)sci.CharAt(position-2) == '"') { sci.SetSel(position - 2, position); sci.ReplaceSel("\""); } // Allow another plugin to handle this de = new DataEvent(EventType.Command, "XMLCompletion.AttributeValue", new XMLContextTag()); EventManager.DispatchEvent(PluginBase.MainForm, de); } else { c = (Char)sci.CharAt(position - 1); if (c == '"' && (Char)sci.CharAt(position) == '"') { sci.SetSel(position - 1, position + 1); sci.ReplaceSel("\""); } } } break; case '?': case '%': if (PluginSettings.CloseTags && position > 1) { ctag = GetXMLContextTag(sci, position-2); if (ctag.Tag == null || ctag.Tag.EndsWith(">")) { if ((Char)sci.CharAt(position-2) == '<') { sci.ReplaceSel((Char)value + ">"); sci.SetSel(position, position); } } } break; case '!': if (PluginSettings.CloseTags && position > 1) { ctag = GetXMLContextTag(sci, position-2); if (ctag.Tag == null || ctag.Tag.EndsWith(">")) { if ((Char)sci.CharAt(position-2) == '<') { CompletionList.Show(xmlBlocks, true); } } } break; } }
public static void GenerateExtractVariable(ScintillaControl sci, string newName) { string expression = sci.SelText.Trim(new char[] { '=', ' ', '\t', '\n', '\r', ';', '.' }); expression = expression.TrimEnd(new char[] { '(', '[', '{', '<' }); expression = expression.TrimStart(new char[] { ')', ']', '}', '>' }); var cFile = ASContext.Context.CurrentModel; ASFileParser parser = new ASFileParser(); parser.ParseSrc(cFile, sci.Text); MemberModel current = cFile.Context.CurrentMember; string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; int funcBodyStart = GetBodyStart(current.LineFrom, current.LineTo, sci); sci.SetSel(funcBodyStart, sci.LineEndPosition(current.LineTo)); string currentMethodBody = sci.SelText; var insertPosition = funcBodyStart + currentMethodBody.IndexOfOrdinal(expression); var line = sci.LineFromPosition(insertPosition); insertPosition = sci.LineIndentPosition(line); int lastPos = -1; sci.Colourise(0, -1); while (true) { lastPos = currentMethodBody.IndexOfOrdinal(expression, lastPos + 1); if (lastPos > -1) { char prevOrNextChar; if (lastPos > 0) { prevOrNextChar = currentMethodBody[lastPos - 1]; if (characterClass.IndexOf(prevOrNextChar) > -1) { continue; } } if (lastPos + expression.Length < currentMethodBody.Length) { prevOrNextChar = currentMethodBody[lastPos + expression.Length]; if (characterClass.IndexOf(prevOrNextChar) > -1) { continue; } } var pos = funcBodyStart + lastPos; int style = sci.BaseStyleAt(pos); if (ASComplete.IsCommentStyle(style)) continue; sci.SetSel(pos, pos + expression.Length); sci.ReplaceSel(newName); currentMethodBody = currentMethodBody.Substring(0, lastPos) + newName + currentMethodBody.Substring(lastPos + expression.Length); lastPos += newName.Length; } else { break; } } sci.CurrentPos = insertPosition; sci.SetSel(sci.CurrentPos, sci.CurrentPos); MemberModel m = new MemberModel(newName, "", FlagType.LocalVar, 0); m.Value = expression; string snippet = TemplateUtils.GetTemplate("Variable"); snippet = TemplateUtils.ReplaceTemplateVariable(snippet, "Modifiers", null); snippet = TemplateUtils.ToDeclarationString(m, snippet); snippet += NewLine + "$(Boundary)"; SnippetHelper.InsertSnippetText(sci, sci.CurrentPos, snippet); }