/// <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> public static void UpdateFunctionPrototypesIfNeeded(bool silent = false) { if (_ignoredFiles.Contains(Plug.CurrentFilePath) || Config.Instance.DisablePrototypeAutoUpdate) { if (silent) { return; } _ignoredFiles.Remove(Plug.CurrentFilePath); } 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) { Npp.BeginUndoAction(); // Add proto if (listOfSoloImplementation.Count > 0) { 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++; } 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++; } GetPrototypesLists(out listOfOutDatedProto, out listOfSoloImplementation, out listOfUselessProto); nbLoop++; } outputMessage.Append("<br><br>"); } // update proto if (listOfOutDatedProto.Count > 0 && nbLoop <= nbToDo) { outputMessage.Append("The following functions have had their prototype synchronized :"); while (listOfOutDatedProto.Count > 0) { if (UpdatePrototypes(ref outputMessage, listOfOutDatedProto[0])) { nbThingsDone++; } GetPrototypesLists(out listOfOutDatedProto, out listOfSoloImplementation, out listOfUselessProto); nbLoop++; } outputMessage.Append("<br><br>"); } Npp.EndUndoAction(); } if (nbThingsDone == 0) { if (!silent) { if (nbNotCreated == 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" + ProCodeFormat.GetParserErrorDescription(), MessageImg.MsgHighImportance, "Function prototypes", "Failed to create prototypes"); } } } else { outputMessage.Append("<i>"); outputMessage.Append("CTRL + Z will cancel the above-mentionned modifications<br>"); outputMessage.Append(Plug.CurrentFilePath.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], Int32.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>" + Plug.CurrentFilePath + "<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); } } }, 5); } }
/// <summary> /// Call this method to insert a new piece of code /// </summary> public static void InsertCode <T>() where T : ParsedScopeItem { IProCode codeCode; string insertText; string blockDescription; // in case of an incorrect document, warn the user if (ParserHandler.AblParser.ParserErrors.Count > 0) { if (UserCommunication.Message("The internal parser of 3P has found inconsistencies in your document :<br>" + ProCodeFormat.GetParserErrorDescription() + "<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; 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; } // make sure to parse the current document before checking anything ParserHandler.ParseCurrentDocument(true, true); // check if the code already exists if (ParserHandler.AblParser.ParsedItemsList.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 = Npp.GetPosFromLineColumn(Npp.Line.CurrentLine, 0); } insertText = FormatInsertion(insertText, blockDescription, insertBefore); int internalCaretPos = insertText.IndexOf("|||", StringComparison.Ordinal); insertText = insertText.Replace("|||", ""); Npp.SetSelection(insertPos); Npp.ModifyTextAroundCaret(0, 0, insertText); Npp.GoToLine(Npp.LineFromPosition(insertPos)); Npp.GotoPosition(insertPos + (internalCaretPos > 0 ? internalCaretPos : 0)); // in the case of a new function, create the prototype if needed if (typeof(ParsedImplementation) == typeof(T)) { UpdateFunctionPrototypesIfNeeded(true); } }