예제 #1
0
        /// <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);
        }