/// <summary> /// returns the best caret position for inserting a new IProNew /// </summary> private int GetCaretPositionForInsertion <T>(string codeName, ProInsertPosition insertPos, out bool insertBefore) where T : ParsedScopeBlock { insertBefore = false; // at caret position if (insertPos == ProInsertPosition.CaretPosition) { return(Sci.GetPosFromLineColumn(Sci.Line.CurrentLine, 0)); } T refItem = null; #region set insertBefore and refItem // the following is a little annoying to code and understand... // the idea is to get (or dont get if it doesn't exist) the previous or the next item // of type T in the existing list of said types so we can "anchor" on it to insert // our new stuff... if (typeof(ParsedPrototype) == typeof(T)) { // find the previous/next function implementation with a prototype bool found = false; ParsedImplementation foundImplement = null; foreach (var impl in _parsedItems.Where(item => item is ParsedImplementation).Cast <ParsedImplementation>()) { if (impl != null) { // we didn't match our current function implementation yet if (!found) { // we just did if (impl.Name.Equals(codeName)) { found = true; continue; } // set previous item if (impl.HasPrototype) { foundImplement = impl; } } else { // match first item after we found our implementation if (impl.HasPrototype) { insertBefore = true; foundImplement = impl; break; } } } } // now we need its proto if (foundImplement != null) { refItem = _parsedItems.FirstOrDefault(fun => { var proto = fun as ParsedPrototype; return(proto != null && proto.Name.Equals(foundImplement.Name) && proto.SimpleForward); }) as T; } } else { // list of existing items of the same type var existingList = _parsedItems.Where(item => item.GetType() == typeof(T)).Select(item => (T)item).ToList(); if (existingList.Count > 0) { // alphabetical order if (insertPos == ProInsertPosition.AlphabeticalOrder) { // find the position that would take our new code int index = existingList.Select(item => item.Name).ToList().BinarySearch(codeName); if (index < 0) { index = ~index - 1; // we get the index in which it should be inserted - 1 if (index == -1) { insertBefore = true; refItem = existingList[0]; } else { refItem = existingList[index]; } } // first of its kind } else if (insertPos == ProInsertPosition.First) { refItem = existingList.FirstOrDefault(); insertBefore = true; } else if (insertPos == ProInsertPosition.Last) { refItem = existingList.LastOrDefault(); } } } #endregion string preProcBlockType = null; string typeComment = null; if (typeof(ParsedImplementation) == typeof(T)) { preProcBlockType = @"_FUNCTION"; typeComment = @"Function\s+Implementations"; } else if (typeof(ParsedPrototype) == typeof(T)) { preProcBlockType = @"_FUNCTION-FORWARD"; typeComment = @"Function\s+Prototypes"; } else if (typeof(ParsedProcedure) == typeof(T)) { preProcBlockType = @"_PROCEDURE"; typeComment = @"Internal\s+Procedures"; } // is there already an item existing? if (refItem != null && preProcBlockType != null) { // try to find a &IF DEFINED(EXCLUDE- block or a _UIB_BLOCK that surrounds the prototype var surroundingScope = GetPreProcBlock(refItem, preProcBlockType); if (surroundingScope != null) { return(insertBefore ? surroundingScope.Position : surroundingScope.EndBlockPosition); } // otherwise return the position of the function itself return(insertBefore ? refItem.Position : refItem.EndBlockPosition); } // can we find a comment indicating where the proc should be inserted? if (typeComment != null) { Sci.TargetWholeDocument(); var previousFlags = Sci.SearchFlags; Sci.SearchFlags = SearchFlags.Regex; var streg = @"\/\*\s+[\*]+\s+" + typeComment + @"\s+[\*]+"; var foundPos = Sci.SearchInTarget(streg); Sci.SearchFlags = previousFlags; if (foundPos == -1) { foundPos = new Regex(@"\/\*\s+[\*]+\s+" + typeComment + @"\s+[\*]+").Match(Sci.Text).Index; if (foundPos == 0) { foundPos = -1; } } if (foundPos > -1) { return(Sci.GetPosFromLineColumn(Sci.LineFromPosition(foundPos) + 1, 0)); } } // At last, we find the best position considering the appbuilder blocks if (typeof(ParsedImplementation) == typeof(T)) { // function implementation goes all the way bottom return(Sci.TextLength); } if (typeof(ParsedPrototype) == typeof(T)) { // prototypes go after &ANALYZE-SUSPEND _UIB-PREPROCESSOR-BLOCK var preprocessorBlock = _parsedItems.FirstOrDefault(item => item is ParsedScopePreProcBlock && ((ParsedScopePreProcBlock)item).Type == ParsedPreProcBlockType.UibPreprocessorBlock); if (preprocessorBlock != null) { insertBefore = false; return(((ParsedScopePreProcBlock)preprocessorBlock).EndBlockPosition); } } if (typeof(ParsedProcedure) == typeof(T)) { // new procedure goes before the first function implementation of last var firstFunc = _parsedItems.FirstOrDefault(item => item is ParsedImplementation) as ParsedImplementation; if (firstFunc != null) { insertBefore = true; // try to find a &IF DEFINED(EXCLUDE- block that surrounds the func var surroundingScope = GetPreProcBlock(firstFunc, @"_FUNCTION"); if (surroundingScope != null) { return(surroundingScope.Position); } return(firstFunc.Position); } // otherwise it goes at the end return(Sci.TextLength); } return(-1); }