コード例 #1
0
ファイル: FileExplorerForm.cs プロジェクト: zhitian/3P
 private void BtClearAllErrorsOnButtonPressed(object sender, EventArgs buttonPressedEventArgs)
 {
     OpenedFilesInfo.ClearAllErrors(Npp.CurrentFileInfo.Path);
     Sci.GrabFocus();
 }
コード例 #2
0
ファイル: AutoCompletion.cs プロジェクト: niandy/3P
        /// <summary>
        /// This function handles the display of the autocompletion form, create or update it
        /// </summary>
        private static void ShowSuggestionList(AutoCompletionForm form)
        {
            // we changed the list of items to display
            if (_needToSetItems)
            {
                DoInLock(() => {
                    form.SetItems(CurrentItems.Cast <ListItem>().ToList());
                });
                _needToSetItems = false;
            }

            // only activate certain types
            if (_needToSetActiveTypes)
            {
                switch (CurrentActiveTypes)
                {
                case ActiveTypes.All:
                    form.SetUnactiveType(new List <int> {
                        (int)CompletionType.KeywordObject
                    });
                    break;

                case ActiveTypes.KeywordObject:
                    form.SetActiveType(new List <int> {
                        (int)CompletionType.KeywordObject
                    });
                    break;

                default:
                    form.SetUnactiveType(null);
                    break;
                }
            }

            // the filter uses the current caret line to know which item should be filtered, set it here
            int nppCurrentLine = Sci.Line.CurrentLine;

            CompletionFilterClass.Instance.UpdateConditions(nppCurrentLine);

            // filter with keyword (keyword can be empty)
            form.SetFilterString(_currentWord);

            // close if the list ends up empty after the filter
            if (!_openedFromShortCut && Config.Instance.AutoCompleteOnKeyInputHideIfEmpty && form.GetNbItems() == 0)
            {
                Cloak();
                return;
            }

            // if the form was already visible, don't go further
            if (IsVisible)
            {
                return;
            }

            // update form position
            var lineHeight = Sci.TextHeight(nppCurrentLine);
            var point      = Sci.GetCaretScreenLocation();

            point.Y += lineHeight;

            form.SetPosition(point, lineHeight + 2, WinApi.GetWindowRect(Npp.CurrentSci.Handle));
            form.UnCloak();
            form.SetSelectedIndex(0);
            form.SetCaseMode(FilterCaseMode);

            _shownPosition = Sci.CurrentPosition;
        }
コード例 #3
0
 /// <summary>
 /// returns the number of chars between two lines in the current document
 /// </summary>
 private static int NbExtraCharBetweenLines(int startLine, int endLine)
 {
     return((Sci.StartBytePosOfLine(endLine) - Sci.StartBytePosOfLine(startLine)) - Config.Instance.GlobalMaxNbCharInBlock);
 }
コード例 #4
0
        public override string ToString()
        {
            var toDisplay = new StringBuilder();

            toDisplay.Append(HtmlHelper.FormatRow("Type of keyword", HtmlHelper.FormatSubString(SubText)));

            // for abbreviations, find the complete keyword first
            string keyword = DisplayText;

            if (!string.IsNullOrEmpty(_fullWord))
            {
                toDisplay.Append(HtmlHelper.FormatRow("Abbreviation of", HtmlHelper.FormatSubString(FullWord)));
            }

            string keyToFind = string.Join(" ", DisplayText, KeywordType);

            // for the keywords define and create, we try to match the second keyword that goes with it
            if (KeywordType == KeywordType.Statement && (keyword.EqualsCi("define") || keyword.EqualsCi("create")))
            {
                var lineStr        = Sci.GetLine(Sci.LineFromPosition(Sci.GetPositionFromMouseLocation())).LineText;
                var listOfSecWords = new List <string> {
                    "ALIAS", "BROWSE", "BUFFER", "BUTTON", "CALL", "CLIENT-PRINCIPAL", "DATA-SOURCE", "DATABASE", "DATASET", "EVENT", "FRAME", "IMAGE", "MENU", "PARAMETER", "PROPERTY", "QUERY", "RECTANGLE", "SAX-ATTRIBUTES", "SAX-READER", "SAX-WRITER", "SERVER", "SERVER-SOCKET", "SOAP-HEADER", "SOAP-HEADER-ENTRYREF", "SOCKET", "STREAM", "SUB-MENU", "TEMP-TABLE", "VARIABLE", "WIDGET-POOL", "WORK-TABLE", "WORKFILE", "X-DOCUMENT", "X-NODEREF"
                };
                foreach (var word in listOfSecWords)
                {
                    if (lineStr.ContainsFast(word))
                    {
                        keyToFind = string.Join(" ", keyword, word, KeywordType);
                        break;
                    }
                }
            }

            var dataHelp = Keywords.Instance.GetKeywordHelp(keyToFind);

            if (dataHelp != null)
            {
                toDisplay.Append(HtmlHelper.FormatSubtitle("DESCRIPTION"));
                toDisplay.Append(dataHelp.Description);

                // synthax
                if (dataHelp.Synthax.Count >= 1 && !string.IsNullOrEmpty(dataHelp.Synthax[0]))
                {
                    toDisplay.Append(HtmlHelper.FormatSubtitle("SYNTAX"));
                    toDisplay.Append(@"<div class='ToolTipcodeSnippet'>");
                    var i = 0;
                    foreach (var synthax in dataHelp.Synthax)
                    {
                        if (i > 0)
                        {
                            toDisplay.Append(@"<br>");
                        }
                        toDisplay.Append(synthax);
                        i++;
                    }
                    toDisplay.Append(@"</div>");
                }
            }
            else
            {
                toDisplay.Append(HtmlHelper.FormatSubtitle("404 NOT FOUND"));
                if (KeywordType == KeywordType.Option)
                {
                    toDisplay.Append("<i><b>Sorry, this keyword doesn't have any help associated</b><br>Since this keyword is an option, try to hover the first keyword of the statement or refer to the 4GL help</i>");
                }
                else
                {
                    toDisplay.Append("<i><b>Sorry, this keyword doesn't have any help associated</b><br>Please refer to the 4GL help</i>");
                }
            }

            return(toDisplay.ToString());
        }
コード例 #5
0
ファイル: AutoCompletion.cs プロジェクト: niandy/3P
        /// <summary>
        /// Updates the CURRENT ITEMS LIST,
        /// handles the opening or the closing of the auto completion form on key input
        /// (externally called when a new char is entered or when a char is deleted)
        /// </summary>
        public static void UpdateAutocompletion(char c = char.MinValue, int insertPosition = -1)
        {
            if (_insertingWord)
            {
                return;
            }

            var typing    = IsCharPartOfWord(c);
            var isVisible = IsVisible;

            // currently continuing to type a word in a visible auto completion, return asap
            if (typing && isVisible)
            {
                // the auto completion is already visible, this means the _currentWord is set
                // we only have to filter the current list even more
                ShowSuggestionList(_currentWord + c);
                return;
            }

            var    nppCurrentPosition = Sci.CurrentPosition;
            var    nppCurrentLine     = Sci.Line.CurrentLine;
            var    isNormalContext    = SyntaxHighlight.IsCarretInNormalContext(nppCurrentPosition);
            string strOnLeft          = null;

            //----------------------
            // we finished entering a word (we typed a char that is not part of a word, a space of new line or separator...)
            //----------------------
            if (c != char.MinValue && !typing && isNormalContext)
            {
                strOnLeft = Sci.GetTextOnLeftOfPos(nppCurrentPosition, 61);
                var strOnLeftLength = strOnLeft.Length;

                // we finished entering a word, find the offset at which we can find said word
                int offset = 1;
                if (c == '\r' || c == '\n')
                {
                    offset = nppCurrentPosition - insertPosition;
                    if (offset > 40)
                    {
                        // case of an extremely hard tabbed line
                        strOnLeft = Sci.GetTextOnLeftOfPos(nppCurrentPosition - offset, 61);
                    }
                }

                bool textHasChanged = false;

                if (offset > 0 && strOnLeftLength > offset)
                {
                    bool hasAtLeastOneLetter = false;
                    bool hasAtLeastOneDigit  = false;
                    var  checkOffset         = offset;
                    while (strOnLeftLength - 1 - checkOffset > 0 && IsCharPartOfWord(strOnLeft[strOnLeftLength - 1 - checkOffset]))
                    {
                        var ch = strOnLeft[strOnLeftLength - 1 - checkOffset];
                        if (char.IsDigit(ch))
                        {
                            hasAtLeastOneDigit = true;
                        }
                        if (char.IsLetter(ch))
                        {
                            hasAtLeastOneLetter = true;
                            break;
                        }
                        checkOffset++;
                    }

                    // See if the char of the "word" we finished entering is actually part of a word
                    // (maybe not if, for instance, we just input 2 spaces consecutively)
                    if (hasAtLeastOneLetter || (hasAtLeastOneDigit && !Npp.CurrentFileInfo.IsProgress && !Config.Instance.NppAutoCompleteIgnoreNumbers))
                    {
                        // automatically insert selected keyword of the completion list?
                        if (InsertSelectedSuggestionOnWordEnd && isVisible)
                        {
                            InsertSuggestion(_form.GetCurrentCompletionItem(), -offset);
                            textHasChanged = true;
                        }

                        // automatically change the case of the keyword?
                        else if (AutoCase && (nppCurrentPosition - offset) != _positionOfLastInsertion)
                        {
                            var candidates = FindInCompletionData(strOnLeft.Substring(0, strOnLeftLength - offset), nppCurrentLine);
                            // we matched the word in the list, correct the case
                            if (candidates != null && candidates.Count > 0)
                            {
                                InsertSuggestion(candidates.First(), -offset);
                                textHasChanged = true;
                            }
                        }
                    }
                }

                // replace semicolon by a point
                if (c == ';' && Config.Instance.AutoCompleteReplaceSemicolon && Npp.CurrentFileInfo.IsProgress)
                {
                    _insertingWord           = true;
                    _positionOfLastInsertion = Sci.ModifyTextAroundCaret(-1, 0, ".");
                    _insertingWord           = false;
                    textHasChanged           = true;
                }

                // need to update the strOnLeft since we use it again in this method
                if (textHasChanged)
                {
                    nppCurrentPosition = Sci.CurrentPosition;
                    strOnLeft          = Sci.GetTextOnLeftOfPos(nppCurrentPosition, 61);
                }
            }

            //----------------------
            // We are here if the auto completion is hidden or if the user is not continuing to type a word,
            // So we have the opportunity to change the list of items in the auto completion if needed
            //----------------------

            if (!_openedFromShortCut)
            {
                // don't automatically show the auto completion on input?
                if (!Config.Instance.AutoCompleteOnKeyInputShowSuggestions)
                {
                    return;
                }

                // don't show in string/comments..?
                if (!isVisible && !isNormalContext && !Config.Instance.AutoCompleteShowInCommentsAndStrings)
                {
                    return;
                }
            }
            else
            {
                // the caret changed line (happens when we trigger the auto comp manually on the first position of a line
                // and we press backspace, we return to the previous line but the form would still be visible)
                if (isVisible && nppCurrentLine != _openedFromShortcutLine)
                {
                    Cloak();
                    return;
                }
            }

            // get current word
            if (strOnLeft == null)
            {
                strOnLeft = Sci.GetTextOnLeftOfPos(nppCurrentPosition, 61);
            }
            int  charPos = 0;
            char?firstSeparator;
            var  firstKeyword = GetWord(strOnLeft, ref charPos, out firstSeparator);

            if (typing)
            {
                // (form is not visible if we are here) Min length is not reached?
                if (!_openedFromShortCut && firstKeyword.Length < Config.Instance.AutoCompleteStartShowingListAfterXChar)
                {
                    return;
                }
            }

            if (firstSeparator == null)
            {
                // we didn't match a known separator just before the keyword;
                // this means we want to display the entire list of keywords

                if (CurrentActiveTypes != ActiveTypes.All)
                {
                    CurrentActiveTypes = ActiveTypes.All;
                    DoInLock(() => { CurrentItems = _savedAllItems; });
                }
            }
            else
            {
                // return the list of children that should be used in the auto completion, filtered by the previous keywords
                List <CompletionItem> outList = null;
                DoInLock(() => {
                    var filterClass = new CompletionFilterClass();
                    filterClass.UpdateConditions(nppCurrentLine);
                    outList = GetWordsList(_savedAllItems.Where(filterClass.FilterPredicate), strOnLeft, charPos, firstSeparator).ToList();
                });

                // empty list?
                if (outList == null || outList.Count == 0)
                {
                    // if the current word is directly preceded by a :, we are entering an object field/method
                    // for now, we then display the whole list of object keywords
                    if (firstSeparator == ':' && Npp.CurrentFileInfo.IsProgress)
                    {
                        if (CurrentActiveTypes != ActiveTypes.KeywordObject)
                        {
                            CurrentActiveTypes = ActiveTypes.KeywordObject;
                            DoInLock(() => { CurrentItems = _savedAllItems; });
                        }
                        ShowSuggestionList(firstKeyword);
                        return;
                    }

                    // we should consider the first separator found not as a child separator, display the whole list
                    if (CurrentActiveTypes != ActiveTypes.All)
                    {
                        CurrentActiveTypes = ActiveTypes.All;
                        DoInLock(() => { CurrentItems = _savedAllItems; });
                    }
                }
                else
                {
                    // we will display the list filtered with all the needed children
                    CurrentActiveTypes = ActiveTypes.Filtered;
                    DoInLock(() => {
                        CurrentItems = outList.ToList();
                        CurrentItems.Sort(CompletionSortingClass <CompletionItem> .Instance);
                    });

                    // we want to show the list no matter how long the filter keyword
                    if (Config.Instance.AutoCompleteShowChildrenAfterSeparator)
                    {
                        ShowSuggestionList(firstKeyword);
                        return;
                    }
                }
            }

            // check if the minimum length of word is ok
            if (isVisible)
            {
                // close if (we didn't open from shortcut or we are not at the opening position) and the min length is not reached
                if ((!_openedFromShortCut || nppCurrentPosition < _shownPosition) && firstKeyword.Length < Config.Instance.AutoCompleteStartShowingListAfterXChar)
                {
                    Cloak();
                    return;
                }
                // auto completion from shortcut at the end of a word and we press space, we need to close it!
                if (_openedFromShortCut && nppCurrentPosition > _shownPosition && c != char.MinValue)
                {
                    Cloak();
                    return;
                }
            }
            else
            {
                // Min length is not reached?
                if (!_openedFromShortCut && firstKeyword.Length < Config.Instance.AutoCompleteStartShowingListAfterXChar)
                {
                    return;
                }
            }

            ShowSuggestionList(firstKeyword);
        }
コード例 #6
0
ファイル: Snippets.cs プロジェクト: zhitian/3P
        static public bool NavigateToNextParam()
        {
            var indic = Sci.GetIndicator(SnippetContext.IndicatorId);

            indic.IndicatorStyle = IndicatorStyle.Box;
            indic.ForeColor      = Color.Blue;

            var indicators = indic.FindRanges().ToArray();

            if (!indicators.Any())
            {
                return(false);
            }

            if (LocSnippetContext.CurrentParameter != null)
            {
                Point  currentParam             = LocSnippetContext.CurrentParameter.Value;
                string currentParamOriginalText = LocSnippetContext.CurrentParameterValue;

                Sci.SetSelection(currentParam.X, currentParam.X);
                string currentParamDetectedText = Sci.GetWordAtPosition(Sci.CurrentPosition, AutoCompletion.CurrentLangAdditionalChars);

                if (currentParamOriginalText != currentParamDetectedText)
                {
                    //current parameter is modified, indicator is destroyed so restore the indicator first
                    indic.Add(currentParam.X, currentParam.X + currentParamDetectedText.Length);

                    indicators = indic.FindRanges().ToArray(); //needs refreshing as the document is modified

                    var paramsInfo = indicators.Select(p => new {
                        Index = indicators.IndexOf(p),
                        Text  = Sci.GetTextBetween(p),
                        Range = p,
                        Pos   = p.X
                    })
                                     .OrderBy(x => x.Pos)
                                     .ToArray();

                    var paramsToUpdate = paramsInfo.Where(item => item.Text == currentParamOriginalText).ToArray();

                    foreach (var param in paramsToUpdate)
                    {
                        ReplaceTextAtIndicator(currentParamDetectedText, indicators[param.Index]);
                        indicators = indic.FindRanges().ToArray(); //needs refreshing as the document is modified
                    }
                }

                Point?nextParameter = null;

                int currentParamIndex = indicators.FindIndex(x => x.X >= currentParam.X); //can also be logical 'next'
                var prevParamsValues  = indicators.Take(currentParamIndex).Select(p => Sci.GetTextBetween(p)).ToList();
                prevParamsValues.Add(currentParamOriginalText);
                prevParamsValues.Add(currentParamDetectedText);
                prevParamsValues.Add(" ");
                prevParamsValues.Add("|");

                foreach (var range in indicators.ToArray())
                {
                    if (currentParam.X < range.X && !prevParamsValues.Contains(Sci.GetTextBetween(range)))
                    {
                        nextParameter = range;
                        break;
                    }
                }

                if (!nextParameter.HasValue)
                {
                    nextParameter = indicators.FirstOrDefault();
                }

                LocSnippetContext.CurrentParameter = nextParameter;
            }
            if (LocSnippetContext.CurrentParameter.HasValue)
            {
                Sci.SetSelection(LocSnippetContext.CurrentParameter.Value.X, LocSnippetContext.CurrentParameter.Value.Y);
                LocSnippetContext.CurrentParameterValue = Sci.GetTextBetween(LocSnippetContext.CurrentParameter.Value);
            }

            return(true);
        }
コード例 #7
0
 public void OrganizeImportsFixtureSetUp()
 {
     // Needed for preprocessor directives...
     Sci.SetProperty("fold", "1");
     Sci.SetProperty("fold.preprocessor", "1");
 }
コード例 #8
0
        internal static void DoPlugStart()
        {
            if (OnPlugReady != null)
            {
                OnPlugReady();
            }

            ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

            // subscribe to static events
            ProEnvironment.OnEnvironmentChange += FileExplorer.Instance.RebuildFileList;
            ProEnvironment.OnEnvironmentChange += DataBase.Instance.UpdateDatabaseInfo;
            ProEnvironment.OnEnvironmentChange += ParserHandler.ClearStaticData;

            Keywords.Instance.OnImport         += AutoCompletion.SetStaticItems;
            DataBase.Instance.OnDatabaseUpdate += AutoCompletion.SetStaticItems;
            AutoCompletion.OnUpdateStaticItems += ParserHandler.UpdateKnownStaticItems;

            ParserHandler.OnStart += CodeExplorer.Instance.OnStart;
            ParserHandler.OnEndSendCompletionItems   += AutoCompletion.SetDynamicItems;
            ParserHandler.OnEndSendParserItems       += CodeExplorer.Instance.OnParseEndParserItems;
            ParserHandler.OnEndSendParserItems       += SyntaxFolding.OnParseEndParserItems;
            ParserHandler.OnEndSendCodeExplorerItems += CodeExplorer.Instance.OnParseEndCodeExplorerItems;
            ParserHandler.OnEnd += CodeExplorer.Instance.OnParseEnd;

            ProExecutionHandleCompilation.OnEachCompilationOk += OpenedFilesInfo.ProExecutionHandleCompilationOnEachCompilationOk;

            // Clear the %temp% directory if we didn't do it properly last time
            Utils.DeleteDirectory(Config.FolderTemp, true);

            //Snippets.Init();
            FileCustomInfo.Import();

            DelayedAction.StartNew(100, () => {
                if (Config.Instance.InstallStep == 0)
                {
                    Config.Instance.InstallStep++;

                    // we are at the first notepad++ start
                    Npp.ConfXml.FinishPluginInstall(); // will apply npp options and restart npp
                    return;
                }
                if (Config.Instance.InstallStep == 1)
                {
                    Config.Instance.InstallStep++;

                    // global options applied, we are at the second startup
                    UserCommunication.NotifyUnique("welcome", "Thank you for installing 3P, you are awesome!<br><br>If this is your first look at 3P you should probably read the <b>getting started</b> section of the home page by clicking " + "go".ToHtmlLink("on this link right here") + ".<br><br><div align='right'>And as always... Enjoy!</div>", MessageImg.MsgInfo, "Fresh install", "Hello and welcome aboard!", args => {
                        Appli.ToggleView();
                        UserCommunication.CloseUniqueNotif("welcome");
                        args.Handled = true;
                    });
                }
                else if (!Config.Instance.NppStoppedCorrectly)
                {
                    // Npp didn't stop correctly, if the backup mode is activated, inform the user
                    if (Npp.ConfXml.BackupMode > 0)
                    {
                        UserCommunication.Notify("It seems that notepad++ didn't stop correctly.<br>If you lost some modifications, don't forget that you have a backup folder here :<br><br><div>" + Npp.ConfXml.BackupDirectory.ToHtmlLink() + "</div>" + (Npp.ConfXml.BackupUseCustomDir ? "<div>" + Npp.ConfXml.CustomBackupDirectory.ToHtmlLink() + "</div>" : ""), MessageImg.MsgInfo, "Notepad++ crashed", "Backup folder location");
                    }
                }

                Config.Instance.NppStoppedCorrectly = false;

                // check if an update was done and start checking for new updates
                Updater <MainUpdaterWrapper> .Instance.CheckForUpdateDoneAndStartCheckingForUpdates();

                if (Updater <ProlintUpdaterWrapper> .Instance.LocalVersion.IsHigherVersionThan("v0"))
                {
                    Updater <ProlintUpdaterWrapper> .Instance.StartCheckingForUpdate();
                }
                if (Updater <ProparseUpdaterWrapper> .Instance.LocalVersion.IsHigherVersionThan("v0"))
                {
                    Updater <ProparseUpdaterWrapper> .Instance.StartCheckingForUpdate();
                }

                // Try to update the configuration from the distant shared folder
                ShareExportConf.StartCheckingForUpdates();
            });

            // check if npp version is meeting current recommended version
            if (!string.IsNullOrEmpty(Npp.SoftwareStringVersion) && !Npp.SoftwareStringVersion.IsHigherOrEqualVersionThan(Config.RequiredNppVersion))
            {
                if (!Config.Instance.NppOutdatedVersion)
                {
                    UserCommunication.Notify("This version of 3P has been developed for Notepad++ " + Config.RequiredNppVersion + ", your version (" + Npp.SoftwareStringVersion + ") is outdated.<br><br>Using an outdated version, you might encounter bugs that would not occur otherwise.<br>Try to update your version of Notepad++ as soon as possible, or use 3P at your own risks.<br><br><a href='https://notepad-plus-plus.org/download/'>Download the latest version of Notepad++ here</a>", MessageImg.MsgHighImportance, "Outdated version", "3P requirements are not met");
                    Config.Instance.NppOutdatedVersion = true;
                }
            }
            else
            {
                Config.Instance.NppOutdatedVersion = false;
            }

            // ReSharper disable once ObjectCreationAsStatement
            RecurentAction.StartNew(User.Ping, 1000 * 60 * 120);

            // Make sure to give the focus to scintilla on startup
            Sci.GrabFocus();

            DelayedAction.StartNew(1000, Config.Save);
        }
コード例 #9
0
        /// <summary>
        /// handles the notifications send by npp and scintilla to the plugin
        /// </summary>
        public static void OnNppNotification(SCNotification nc)
        {
            try {
                uint code = nc.nmhdr.code;

                // Plugin waiting to be started...
                if (!PluginIsReady)
                {
                    switch (code)
                    {
                    case (uint)NppNotif.NPPN_TBMODIFICATION:
                        // this is the event that we want to respond to, it sets the toolbar icons
                        UnmanagedExports.NppFuncItems.RefreshItems();
                        Plug.DoNppNeedToolbarImages();
                        return;

                    case (uint)NppNotif.NPPN_READY:
                        // notify plugins that all the procedures of launch of notepad are done
                        ActionsAfterUpdateUi = new Queue <Action>();
                        Npp.UpdateCurrentSci();     // init current scintilla
                        UiThread.Init();
                        PluginIsReady = Plug.DoNppReady();
                        // call OnNppReady then OnPlugReady if it all went ok
                        if (PluginIsReady)
                        {
                            Plug.DoPlugStart();
                            OnNppNotification(new SCNotification((uint)NppNotif.NPPN_BUFFERACTIVATED));      // simulate buffer activated

                            // set hooks on mouse/keyboard
                            SetHooks();
                        }
                        return;

                    case (uint)NppNotif.NPPN_SHUTDOWN:
                        // uninstall hooks on mouse/keyboard
                        UninstallHooks();
                        UiThread.Close();
                        Plug.DoNppShutDown();
                        return;

                    case (uint)NppNotif.NPPN_CANCELSHUTDOWN:
                        PluginIsReady = true;
                        return;
                    }
                }
                else
                {
                    // the plugin is fully loaded and ready to do stuff

                    if ((uint)SciNotif.SCN_NOTIF_BEGIN < code && code < (uint)SciNotif.SCN_NOTIF_END)
                    {
                        switch (code)
                        {
                        // --------------------------------------------------------
                        // Scintilla message
                        // --------------------------------------------------------
                        case (uint)SciNotif.SCN_CHARADDED:
                            // called each time the user add a char in the current scintilla
                            // It's actually better to use the SCI_MODIFIED instead, this notification
                            // is not always called when it should! (ex not called for /t)
                            return;

                        case (uint)SciNotif.SCN_UPDATEUI:
                            while (ActionsAfterUpdateUi.Any())
                            {
                                ActionsAfterUpdateUi.Dequeue()();
                            }
                            Plug.OnSciUpdateUi(nc);
                            return;

                        case (uint)SciNotif.SCN_MODIFIED:
                            // This notification is sent when the text or styling of the document changes or is about to change
                            // (note : this notif isn't sent when the user SWITCHES to tab file (already opened in another tab) !
                            // But it is sent when the user opens a NEW file)
                            bool deletedText            = (nc.modificationType & (int)SciModificationMod.SC_MOD_DELETETEXT) != 0;
                            bool insertedText           = (nc.modificationType & (int)SciModificationMod.SC_MOD_INSERTTEXT) != 0;
                            bool undo                   = (nc.modificationType & (int)SciModificationMod.SC_PERFORMED_UNDO) != 0;
                            bool redo                   = (nc.modificationType & (int)SciModificationMod.SC_PERFORMED_REDO) != 0;
                            bool singleCharModification = false;

                            if ((insertedText || deletedText) && !ScnModifiedDisabled)
                            {
                                var encoding = Sci.Encoding;
                                Npp.CurrentSci.Lines.OnScnModified(nc, !deletedText, encoding);     // register line modifications
                                if (!undo && !redo)
                                {
                                    // if the text has changed
                                    unsafe {
                                        var nbCarets = Sci.Selection.Count;
                                        if (_currentCaret > 0)
                                        {
                                            _currentCaret++;
                                            if (_currentCaret <= nbCarets)
                                            {
                                                return;
                                            }
                                            // then it is the first caret again, we can handle the char
                                            _currentCaret = 0;
                                        }
                                        if (nbCarets > 1)
                                        {
                                            _currentCaret++;
                                        }

                                        // only 1 char appears to be modified
                                        var ncLength = nc.length.ToInt32();
                                        if (ncLength <= 2)
                                        {
                                            // get the char
                                            var bytes   = (byte *)nc.text;
                                            var arrbyte = new byte[ncLength];
                                            int index;
                                            for (index = 0; index < ncLength; index++)
                                            {
                                                arrbyte[index] = bytes[index];
                                            }
                                            var c       = encoding.GetChars(arrbyte);
                                            var cLength = c.Length;
                                            // do we really have a 1 char input?
                                            if (cLength == 1 || (cLength == 2 && c[0] == '\r'))
                                            {
                                                if (insertedText)
                                                {
                                                    ActionsAfterUpdateUi.Enqueue(() => Plug.OnCharAdded(c[0], nc.position.ToInt32()));
                                                }
                                                else
                                                {
                                                    ActionsAfterUpdateUi.Enqueue(() => Plug.OnCharDeleted(c[0], nc.position.ToInt32()));
                                                }
                                                singleCharModification = true;
                                            }
                                        }
                                    }
                                }
                                ActionsAfterUpdateUi.Enqueue(() => Plug.OnTextModified(nc, insertedText, deletedText, singleCharModification, undo, redo));
                            }

                            return;

                        case (uint)SciNotif.SCN_STYLENEEDED:
                            // if we use the contained lexer, we will receive this notification and we will have to style the text
                            Plug.OnStyleNeeded(Sci.GetEndStyled(), nc.position.ToInt32());
                            return;

                        case (uint)SciNotif.SCN_MARGINCLICK:
                            // called each time the user click on a margin
                            Plug.OnSciMarginClick(nc);
                            return;

                        case (uint)SciNotif.SCN_MODIFYATTEMPTRO:
                            // Code a checkout when trying to modify a read-only file
                            return;

                        case (uint)SciNotif.SCN_DWELLSTART:
                            // when the user hover at a fixed position for too long
                            Plug.OnSciDwellStart();
                            return;

                        case (uint)SciNotif.SCN_DWELLEND:
                            // when he moves his cursor
                            Plug.OnSciDwellEnd();
                            return;
                        }
                    }
                    else if ((uint)NppNotif.NPPN_NOTIF_BEGIN < code && code < (uint)NppNotif.NPPN_NOTIF_END)
                    {
                        // --------------------------------------------------------
                        // Npp message
                        // --------------------------------------------------------
                        switch (code)
                        {
                        case (uint)NppNotif.NPPN_BUFFERACTIVATED:
                            // the user changes the current document (this event is called when the current document is switched (via the tabs)
                            // and also when a new file is opened in npp
                            Npp.UpdateCurrentSci();       // update current scintilla
                            Npp.CurrentSci.Lines.Reset(); // register new lines
                            NppBufferActivated();
                            return;

                        case (uint)NppNotif.NPPN_FILERENAMED:
                            // the user can open a .txt and rename it as a .p
                            NppBufferActivated();
                            return;

                        case (uint)NppNotif.NPPN_FILESAVED:
                            // the user can open a .txt and save it as a .p
                            NppBufferActivated();

                            Plug.DoNppDocumentSaved();
                            return;

                        case (uint)NppNotif.NPPN_FILEBEFORELOAD:
                            // fire when a file is opened
                            // When loading a new file into NPP, the events fired are (in order) :
                            // NPPN_FILEBEFORELOAD > SCN_MODIFIED > NPPN_FILEBEFOREOPEN > NPPN_FILEOPENED > NPPN_BUFFERACTIVATED
                            // we deactivate the SCN_MODIFIED between NPPN_FILEBEFORELOAD and NPPN_FILEBEFOREOPEN
                            ScnModifiedDisabled = true;
                            Plug.DoNppFileBeforeLoad();
                            return;

                        case (uint)NppNotif.NPPN_FILEBEFOREOPEN:
                            ScnModifiedDisabled = false;
                            return;

                        case (uint)NppNotif.NPPN_FILEOPENED:
                            // on file opened
                            Plug.OnNppFileOpened();
                            return;

                        case (uint)NppNotif.NPPN_FILEBEFORECLOSE:
                            // on file closed
                            Plug.OnNppFileBeforeClose();
                            return;

                        case (uint)NppNotif.NPPN_LANGCHANGED:
                            // on lang type changed
                            Plug.OnLangChanged();
                            NppBufferActivated();
                            return;

                        case (uint)NppNotif.NPPN_WORDSTYLESUPDATED:
                            // The styles have been modified
                            Npp.StylersXml.Reload();
                            // unfortunatly, if the user changed of styler.xml file (he selected another theme) then we
                            // will incorrectly read the styles since we have to wait for the config.xml to be updated
                            // and it only updates on npp shutdown
                            return;

                        case (uint)NppNotif.NPPN_BEFORESHUTDOWN:
                            // prevent the plugin from handling a lot of events when npp is about to shutdown
                            PluginIsReady = false;
                            return;
                        }
                    }
                }
            } catch (Exception e) {
                ErrorHandler.ShowErrors(e, "Error in beNotified : code = " + nc.nmhdr.code);
            }
        }
コード例 #10
0
ファイル: ProMisc.cs プロジェクト: zhitian/3P
        /// <summary>
        /// Called after the execution of run/compile/check/prolint
        /// </summary>
        public static void OnSingleExecutionOk(ProExecutionHandleCompilation lastExec, List <FileToCompile> filesToCompile, List <FileToDeploy> filesToDeploy)
        {
            try {
                var treatedFile = lastExec.Files.First();
                CurrentOperation currentOperation;
                if (!Enum.TryParse(lastExec.ExecutionType.ToString(), true, out currentOperation))
                {
                    currentOperation = CurrentOperation.Run;
                }

                var isCurrentFile     = treatedFile.SourcePath.EqualsCi(Npp.CurrentFileInfo.Path);
                var otherFilesInError = false;
                int nbWarnings        = 0;
                int nbErrors          = 0;

                // count number of warnings/errors, loop through files > loop through errors in each file
                foreach (var fileInError in filesToCompile.Where(file => file.Errors != null))
                {
                    foreach (var error in fileInError.Errors)
                    {
                        if (error.Level <= ErrorLevel.StrongWarning)
                        {
                            nbWarnings++;
                        }
                        else
                        {
                            nbErrors++;
                        }
                    }
                    otherFilesInError = otherFilesInError || !treatedFile.SourcePath.EqualsCi(fileInError.SourcePath);
                }

                // Prepare the notification content
                var notifTitle    = currentOperation.GetAttribute <CurrentOperationAttr>().Name;
                var notifImg      = (nbErrors > 0) ? MessageImg.MsgError : ((nbWarnings > 0) ? MessageImg.MsgWarning : MessageImg.MsgOk);
                var notifTimeOut  = (nbErrors > 0) ? 0 : ((nbWarnings > 0) ? 10 : 5);
                var notifSubtitle = lastExec.ExecutionType == ExecutionType.Prolint ? (nbErrors + nbWarnings) + " problem" + ((nbErrors + nbWarnings) > 1 ? "s" : "") + " detected" :
                                    (nbErrors > 0) ? nbErrors + " error" + (nbErrors > 1 ? "s" : "") + " found" :
                                    ((nbWarnings > 0) ? nbWarnings + " warning" + (nbWarnings > 1 ? "s" : "") + " found" :
                                     "Syntax correct");

                // when compiling, transferring .r/.lst to compilation dir
                if (filesToDeploy != null)
                {
                    filesToDeploy = lastExec.ProEnv.Deployer.DeployFiles(filesToDeploy, null, null);
                }

                // Notify the user, or not
                if (Config.Instance.CompileAlwaysShowNotification || !isCurrentFile || !Sci.GetFocus() || otherFilesInError)
                {
                    UserCommunication.NotifyUnique(treatedFile.SourcePath, "<div style='padding-bottom: 5px;'>Was " + currentOperation.GetAttribute <CurrentOperationAttr>().ActionText + " :</div>" + ProExecutionCompile.FormatCompilationResultForSingleFile(treatedFile.SourcePath, treatedFile, filesToDeploy), notifImg, notifTitle, notifSubtitle, null, notifTimeOut);
                }
            } catch (Exception e) {
                ErrorHandler.ShowErrors(e, "Error in OnExecutionOk");
            }
        }
コード例 #11
0
ファイル: FilesInfo.cs プロジェクト: massreuy/3P
        /// <summary>
        /// Displays the errors for the current file (if any)
        /// display an annotation with the message below the line + display a marker in the margin
        /// </summary>
        public static void UpdateErrorsInScintilla()
        {
            // Updates the number of errors in the FileExplorer form and the file status
            UpdateFileStatus();

            var currentFilePath = Npp.CurrentFile.Path;
            var marginError     = Sci.GetMargin(ErrorMarginNumber);

            // need to clear scintilla for this file?
            if (_sessionInfo.ContainsKey(currentFilePath) && _sessionInfo[currentFilePath].NeedToCleanScintilla)
            {
                ClearAnnotationsAndMarkers();
                _sessionInfo[currentFilePath].NeedToCleanScintilla = false;
            }

            // check if current file is a progress and if we got info on it
            if (!Npp.CurrentFile.IsProgress || !_sessionInfo.ContainsKey(currentFilePath) || _sessionInfo[currentFilePath].FileErrors == null || _sessionInfo[currentFilePath].FileErrors.Count == 0)
            {
                if (marginError.Width > 0)
                {
                    marginError.Width = 1;
                    marginError.Width = 0;
                }
                // reset annotation to default
                Sci.AnnotationVisible = Plug.AnnotationMode;
                return;
            }

            // activate annotation (if not already done)
            Plug.AnnotationMode = Annotation.Indented;

            // show margin
            if (marginError.Sensitive == false)
            {
                marginError.Sensitive = true;
            }
            if (marginError.Type != MarginType.Symbol)
            {
                marginError.Type = MarginType.Symbol;
            }
            if (marginError.Mask != EveryMarkersMask)
            {
                marginError.Mask = EveryMarkersMask;
            }

            // only show the new errors
            if (_sessionInfo[currentFilePath].HasErrorsNotDisplayed)
            {
                _sessionInfo[currentFilePath].HasErrorsNotDisplayed = false;

                StylerHelper  stylerHelper = new StylerHelper();
                int           lastLine     = -2;
                StringBuilder lastMessage  = new StringBuilder();
                foreach (var fileError in _sessionInfo[currentFilePath].FileErrors)
                {
                    // new line
                    if (lastLine != fileError.Line)
                    {
                        stylerHelper.Clear();
                        lastMessage.Clear();
                        // set marker style now (the first error encountered for a given line is the highest anyway)
                        if (!((int)Sci.GetLine(fileError.Line).MarkerGet()).IsBitSet((int)fileError.Level))
                        {
                            Sci.GetLine(fileError.Line).MarkerAdd((int)fileError.Level);
                        }
                    }
                    else
                    {
                        // append to existing annotation
                        stylerHelper.Style("\n", (byte)fileError.Level);
                        lastMessage.Append("\n");
                    }

                    lastLine = fileError.Line;

                    var mess = fileError.FromProlint ? "Prolint (level " + fileError.ErrorNumber : ("Compilation " + (fileError.Level == ErrorLevel.Critical ? "error" : "warning") + " (n°" + fileError.ErrorNumber);
                    mess += fileError.FromProlint ? "): " : ", col " + fileError.Column + "): ";
                    stylerHelper.Style(mess, (byte)(Style.ErrorAnnotBoldStyleOffset + fileError.Level));
                    lastMessage.Append(mess);

                    mess = fileError.Message.BreakText(140);
                    stylerHelper.Style(mess, (byte)(Style.ErrorAnnotStandardStyleOffset + fileError.Level));
                    lastMessage.Append(mess);

                    if (Config.Instance.GlobalShowDetailedHelpForErrors && !string.IsNullOrEmpty(fileError.Help))
                    {
                        mess = "\nDetailed help: " + fileError.Help.BreakText(140);
                        stylerHelper.Style(mess, (byte)(Style.ErrorAnnotItalicStyleOffset + fileError.Level));
                        lastMessage.Append(mess);
                    }

                    if (fileError.Times > 0)
                    {
                        mess = "\nThis message above appeared " + fileError.Times + " times in the compiler log";
                        stylerHelper.Style(mess, (byte)(Style.ErrorAnnotBoldStyleOffset + fileError.Level));
                        lastMessage.Append(mess);
                    }

                    // set annotation
                    Sci.GetLine(lastLine).AnnotationText   = lastMessage.ToString();
                    Sci.GetLine(lastLine).AnnotationStyles = stylerHelper.GetStyleArray();
                }
            }

            marginError.Width = ErrorMarginWidth + 1;
            marginError.Width = ErrorMarginWidth;
        }
コード例 #12
0
ファイル: ProMisc.cs プロジェクト: zhitian/3P
        /// <summary>
        /// This method allows the user to GOTO a word definition, if a tooltip is opened then it tries to
        /// go to the definition of the displayed word, otherwise it tries to find the declaration of the parsed word under the
        /// caret. At last, it tries to find a file in the propath
        /// </summary>
        public static void GoToDefinition(bool fromMouseClick)
        {
            // if a tooltip is opened, try to execute the "go to definition" of the tooltip first
            if (InfoToolTip.InfoToolTip.IsVisible)
            {
                if (!string.IsNullOrEmpty(InfoToolTip.InfoToolTip.GoToDefinitionFile))
                {
                    Npp.Goto(InfoToolTip.InfoToolTip.GoToDefinitionFile, InfoToolTip.InfoToolTip.GoToDefinitionPoint.X, InfoToolTip.InfoToolTip.GoToDefinitionPoint.Y);
                    InfoToolTip.InfoToolTip.Cloak();
                    return;
                }
                InfoToolTip.InfoToolTip.Cloak();
            }

            // try to go to the definition of the selected word
            var position = fromMouseClick ? Sci.GetPositionFromMouseLocation() : Sci.CurrentPosition;

            if (fromMouseClick && position <= 0)
            {
                return;
            }
            var curWord = Sci.GetWordAtPosition(position, AutoCompletion.CurrentLangAdditionalChars);

            if (string.IsNullOrEmpty(curWord))
            {
                return;
            }

            // match a word in the autocompletion? go to definition
            var listKeywords = AutoCompletion.FindInCompletionData(curWord, Sci.LineFromPosition(position));

            if (listKeywords != null)
            {
                var listItems = listKeywords.Where(item => item.FromParser && item.ParsedBaseItem is ParsedItem).ToList();
                if (listItems.Count > 0)
                {
                    // only one match, then go to the definition
                    if (listItems.Count == 1)
                    {
                        var pItem = listItems.First().ParsedBaseItem as ParsedItem;
                        if (pItem != null)
                        {
                            Npp.Goto(pItem.FilePath, pItem.Line, pItem.Column);
                            return;
                        }
                    }
                    if (listItems.Count > 1)
                    {
                        // otherwise, list the items and notify the user
                        var output = new StringBuilder(@"Found several matching items, please choose the correct one :<br>");
                        foreach (var cData in listItems)
                        {
                            var pItem = listItems.First().ParsedBaseItem as ParsedItem;
                            if (pItem != null)
                            {
                                output.Append("<div>" + (pItem.FilePath + "|" + pItem.Line + "|" + pItem.Column).ToHtmlLink("In " + Path.GetFileName(pItem.FilePath) + " (line " + pItem.Line + ")"));
                                cData.DoForEachFlag((s, flag) => { output.Append("<img style='padding-right: 0px; padding-left: 5px;' src='" + s + "' height='15px'>"); });
                                output.Append("</div>");
                            }
                        }
                        UserCommunication.NotifyUnique("GoToDefinition", output.ToString(), MessageImg.MsgQuestion, "Question", "Go to the definition", args => {
                            Utils.OpenPathClickHandler(null, args);
                            UserCommunication.CloseUniqueNotif("GoToDefinition");
                        }, 0, 500);
                        return;
                    }
                }
            }

            // last resort, try to find a matching file in the propath

            // if in a string, read the whole string

            // try to read all the . and \

            // first look in the propath
            var fullPaths = ProEnvironment.Current.FindFiles(curWord, Config.Instance.FilesPatternProgress.Replace("*", ""));

            if (fullPaths.Count > 0)
            {
                if (fullPaths.Count > 1)
                {
                    var output = new StringBuilder(@"Found several files matching this name, please choose the correct one :<br>");
                    foreach (var fullPath in fullPaths)
                    {
                        output.Append("<div>" + fullPath.ToHtmlLink() + "</div>");
                    }
                    UserCommunication.NotifyUnique("GoToDefinition", output.ToString(), MessageImg.MsgQuestion, "Question", "Open a file", args => {
                        Npp.Goto(args.Link);
                        UserCommunication.CloseUniqueNotif("GoToDefinition");
                        args.Handled = true;
                    }, 0, 500);
                }
                else
                {
                    Npp.Goto(fullPaths[0]);
                }
                return;
            }

            UserCommunication.Notify("Sorry, couldn't go to the definition of <b>" + curWord + "</b>", MessageImg.MsgInfo, "Information", "Failed to find an origin", 5);
        }
コード例 #13
0
        /// <summary>
        /// Method called when the tooltip is opened from the mouse being inactive on scintilla
        /// </summary>
        public static void ShowToolTipFromDwell(bool openTemporary = true)
        {
            if (Config.Instance.ToolTipDeactivate)
            {
                return;
            }
            InitIfneeded();

            var position = Sci.GetPositionFromMouseLocation();

            if (position < 0)
            {
                return;
            }

            // check caret context, dont display a tooltip for comments
            var curContext = (SciStyleId)Sci.GetStyleAt(position);

            if (curContext == SciStyleId.Comment)
            {
                return;
            }

            // sets the tooltip content
            var data = AutoCompletion.FindInCompletionData(Sci.GetWordAtPosition(position, AutoCompletion.CurrentLangAllChars, AutoCompletion.CurrentLangAdditionalChars), Sci.LineFromPosition(position));

            if (data != null && data.Count > 0)
            {
                _currentCompletionList = data;
            }
            else
            {
                return;
            }

            // in strings, only functions trigger the tooltip
            if ((curContext == SciStyleId.DoubleQuote || curContext == SciStyleId.SimpleQuote) && _currentCompletionList.First().Type != CompletionType.Function)
            {
                return;
            }

            SetToolTip();

            // update position
            var point = Sci.GetPointXyFromPosition(position);

            point.Offset(Sci.GetScintillaRectangle().Location);
            var lineHeight = Sci.TextHeight(Sci.Line.CurrentLine);

            point.Y       += lineHeight + 5;
            _form.Location = _form.GetBestAutocompPosition(point, lineHeight + 5);

            _openedFromDwell = openTemporary;
            if (!_form.Visible)
            {
                _form.UnCloak();
            }
        }
コード例 #14
0
ファイル: ProGenerateCode.cs プロジェクト: massreuy/3P
        /// <summary>
        /// Call this method to insert a new piece of code
        /// </summary>
        public void InsertCode <T>() where T : ParsedScopeItem
        {
            IProCode codeCode;
            string   insertText;
            string   blockDescription;

            // in case of an incorrect document, warn the user
            var parserErrors = _parser.ParseErrorsInHtml;

            if (!string.IsNullOrEmpty(parserErrors))
            {
                if (UserCommunication.Message("The internal parser of 3P has found inconsistencies in your document :<br>" + parserErrors + "<br>You can still insert a new piece of code but the insertion position might not be calculated correctly; take caution of what is generated if you decide to go through with it.", MessageImg.MsgQuestion, "Generate code", "Problems spotted", new List <string> {
                    "Continue", "Abort"
                }) != 0)
                {
                    return;
                }
            }

            if (typeof(ParsedImplementation) == typeof(T))
            {
                object input = new ProCodeFunction();
                if (UserCommunication.Input(ref input, "Please provide information about the procedure that will be created", MessageImg.MsgQuestion, "Generate code", "Insert a new function") != 0)
                {
                    return;
                }
                codeCode = (IProCode)input;

                codeCode.Name = codeCode.Name.MakeValidVariableName();

                blockDescription = @"_FUNCTION " + codeCode.Name + " Procedure";
                insertText       = Encoding.Default.GetString(DataResources.FunctionImplementation).Trim();
                insertText       = insertText.Replace("{&type}", ((ProCodeFunction)codeCode).Type);
                insertText       = insertText.Replace("{&private}", ((ProCodeFunction)codeCode).IsPrivate ? " PRIVATE" : "");
            }
            else if (typeof(ParsedProcedure) == typeof(T))
            {
                object input = new ProCodeProcedure();
                if (UserCommunication.Input(ref input, "Please provide information about the procedure that will be created", MessageImg.MsgQuestion, "Generate code", "Insert a new procedure") != 0)
                {
                    return;
                }
                codeCode = (IProCode)input;

                blockDescription = @"_PROCEDURE " + codeCode.Name + " Procedure";
                insertText       = Encoding.Default.GetString(DataResources.InternalProcedure).Trim();
                insertText       = insertText.Replace("{&private}", ((ProCodeProcedure)codeCode).IsPrivate ? " PRIVATE" : "");
            }
            else
            {
                return;
            }

            if (string.IsNullOrEmpty(codeCode.Name))
            {
                return;
            }

            // check if the code already exists
            if (_parsedItems.Exists(item => item.GetType() == typeof(T) && item.Name.EqualsCi(codeCode.Name)))
            {
                UserCommunication.Notify("Sorry, this name is already taken by another existing instance", MessageImg.MsgHighImportance, "Invalid name", "Existing name", 5);
                return;
            }

            insertText = insertText.Replace("{&name}", codeCode.Name);

            // reposition caret and insert
            bool insertBefore;
            int  insertPos = GetCaretPositionForInsertion <T>(codeCode.Name, codeCode.InsertPosition, out insertBefore);

            if (insertPos < 0)
            {
                insertPos = Sci.GetPosFromLineColumn(Sci.Line.CurrentLine, 0);
            }

            insertText = FormatInsertion(insertText, blockDescription, insertBefore);
            int internalCaretPos = insertText.IndexOf("|||", StringComparison.Ordinal);

            insertText = insertText.Replace("|||", "");

            Sci.SetSelection(insertPos);
            Sci.ModifyTextAroundCaret(0, 0, insertText);

            Sci.GoToLine(Sci.LineFromPosition(insertPos));
            Sci.GotoPosition(insertPos + (internalCaretPos > 0 ? internalCaretPos : 0));

            // in the case of a new function, update the prototype if needed
            if (typeof(ParsedImplementation) == typeof(T))
            {
                ParseNow();
                UpdateFunctionPrototypes(true);
            }
        }
コード例 #15
0
ファイル: ProGenerateCode.cs プロジェクト: massreuy/3P
        /// <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 : ParsedScopeItem
        {
            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 preProcBlock = GetPreProcBlock(refItem, preProcBlockType);
                if (preProcBlock != null)
                {
                    return(insertBefore ? preProcBlock.Position : preProcBlock.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 ParsedPreProcBlock && ((ParsedPreProcBlock)item).Type == ParsedPreProcBlockType.UibPreprocessorBlock);
                if (preprocessorBlock != null)
                {
                    insertBefore = false;
                    return(((ParsedPreProcBlock)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 preProcBlock = GetPreProcBlock(firstFunc, @"_FUNCTION");
                    if (preProcBlock != null)
                    {
                        return(preProcBlock.Position);
                    }

                    return(firstFunc.Position);
                }
                // otherwise it goes at the end
                return(Sci.TextLength);
            }

            return(-1);
        }
コード例 #16
0
ファイル: ProGenerateCode.cs プロジェクト: massreuy/3P
        /// <summary>
        /// This method checks if the current document contains function prototypes that are not updated
        /// and correct them if needed
        /// </summary>
        /// <remarks>This method is costly because we parse everything potentially X times, but it's much simpler this way...</remarks>
        private void UpdateFunctionPrototypes(bool silent)
        {
            try {
                List <ParsedImplementation> listOfOutDatedProto;
                List <ParsedImplementation> listOfSoloImplementation;
                List <ParsedPrototype>      listOfUselessProto;

                StringBuilder outputMessage = new StringBuilder();

                var nbLoop       = 0;
                var nbNotCreated = 0;
                var nbThingsDone = 0;
                var nbToDo       = GetPrototypesLists(out listOfOutDatedProto, out listOfSoloImplementation, out listOfUselessProto);

                // if there is at least 1 thing to do
                if (nbToDo > 0)
                {
                    Sci.BeginUndoAction();

                    // Add proto
                    if (listOfSoloImplementation.Count > 0 && string.IsNullOrEmpty(_parser.ParseErrorsInHtml))
                    {
                        var tempMes = new StringBuilder("The following function prototypes have been created :");

                        while (listOfSoloImplementation.Count > nbNotCreated && nbLoop < nbToDo)
                        {
                            if (AddPrototypes(ref tempMes, listOfSoloImplementation[nbNotCreated]))
                            {
                                nbThingsDone++;
                            }
                            else
                            {
                                nbNotCreated++;
                            }

                            ParseNow();
                            GetPrototypesLists(out listOfOutDatedProto, out listOfSoloImplementation, out listOfUselessProto);
                            nbLoop++;
                        }
                        tempMes.Append("<br><br>");
                        if (nbThingsDone > 0)
                        {
                            outputMessage.Append(tempMes);
                        }
                    }

                    // delete proto
                    if (listOfUselessProto.Count > 0)
                    {
                        outputMessage.Append("The following prototypes have been deleted :");
                        while (listOfUselessProto.Count > 0 && nbLoop < nbToDo)
                        {
                            if (DeletePrototypes(ref outputMessage, listOfUselessProto[0]))
                            {
                                nbThingsDone++;
                            }

                            ParseNow();
                            GetPrototypesLists(out listOfOutDatedProto, out listOfSoloImplementation, out listOfUselessProto);
                            nbLoop++;
                        }
                        outputMessage.Append("<br><br>");
                    }

                    // update proto
                    if (listOfOutDatedProto.Count > 0)
                    {
                        outputMessage.Append("The following functions have had their prototype synchronized :");
                        while (listOfOutDatedProto.Count > 0 && nbLoop < nbToDo)
                        {
                            if (UpdatePrototypes(ref outputMessage, listOfOutDatedProto[0]))
                            {
                                nbThingsDone++;
                            }

                            ParseNow();
                            GetPrototypesLists(out listOfOutDatedProto, out listOfSoloImplementation, out listOfUselessProto);
                            nbLoop++;
                        }
                        outputMessage.Append("<br><br>");
                    }

                    Sci.EndUndoAction();
                }

                if (nbThingsDone == 0)
                {
                    if (!silent)
                    {
                        if (nbToDo == 0)
                        {
                            UserCommunication.Notify("There was nothing to be done :<br>All the prototypes match their implementation", MessageImg.MsgInfo, "Function prototypes", "Everything is synchronized", 5);
                        }
                        else
                        {
                            UserCommunication.Notify("Failed to find the prototype for " + nbNotCreated + " function implementations<br>Your document is not correctly formatted for 3P to automatically create them :<br><i>The block _UIB-PREPROCESSOR-BLOCK is missing or the procedure can't be opened in the appbuilder!</i><br><br>Please correct your document manually, then they will all be updated correctly" + _parser.ParseErrorsInHtml, MessageImg.MsgHighImportance, "Function prototypes", "Failed to create prototypes");
                        }
                    }
                }
                else
                {
                    outputMessage.Append("<i>");
                    outputMessage.Append("CTRL + Z will cancel the above-mentioned modifications<br>");
                    outputMessage.Append(Npp.CurrentFile.Path.ToHtmlLink("Click here to stop auto-updating the prototypes for this file"));
                    outputMessage.Append("</i>");
                    UserCommunication.NotifyUnique("Prototype_synchro", outputMessage.ToString(), MessageImg.MsgOk, "Function prototypes", "Synchronization done", args => {
                        var split = args.Link.Split('#');
                        if (split.Length == 2)
                        {
                            Npp.GotoPos(split[0], int.Parse(split[1]));
                            args.Handled = true;
                        }
                        else
                        {
                            if (!_ignoredFiles.Contains(args.Link))
                            {
                                _ignoredFiles.Add(args.Link);
                                UserCommunication.NotifyUnique("Prototype_synchro", "Automatic prototype updates stopped for the file :<br>" + Npp.CurrentFile.Path + "<br><br><i>This is effective until you restart Notepad++<br>You can also trigger an update manually to restart the auto-update</i>", MessageImg.MsgInfo, "Function prototypes", "Synchronization stopped", null, 5);
                                args.Handled = true;
                            }
                        }
                    }, 5);
                }
            } catch (Exception e) {
                ErrorHandler.ShowErrors(e, "Error updating prototypes");
            }
        }