/// <summary> /// Call this on SCN_MODIFIED event from scintilla to update the info on lines /// </summary> public static void UpdateLinesInfo(SCNotification scn, bool isInsertion) { Lines.OnScnModified(scn, isInsertion); }
/// <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; #region Basic notifications switch (code) { case (uint) NppNotif.NPPN_TBMODIFICATION: UnmanagedExports.FuncItems.RefreshItems(); DoNppNeedToolbarImages(); return; case (uint) NppNotif.NPPN_READY: // notify plugins that all the procedures of launchment of notepad++ are done // call OnNppReady then OnPlugReady if it all went ok PluginIsReady = DoNppReady(); if (PluginIsReady) { DoPlugStart(); // set hooks on mouse/keyboard SetHooks(); PluginIsFullyLoaded = true; } return; case (uint) NppNotif.NPPN_SHUTDOWN: // uninstall hooks on mouse/keyboard UninstallHooks(); DoNppShutDown(); PluginIsReady = false; return; } #endregion // Only do stuff when the dll is fully loaded if (!PluginIsReady) return; switch (code) { // the user changed the current document case (uint) NppNotif.NPPN_BUFFERACTIVATED: DoNppBufferActivated(); return; case (uint)NppNotif.NPPN_FILESAVED: DoNppDocumentSaved(); return; case (uint)NppNotif.NPPN_FILEBEFORELOAD: // fire when a file is opened (the event NPPN_FILEBEFOREOPEN is fired after SciNotif.SCN_MODIFIED // and just before NppNotif.NPPN_BUFFERACTIVATED so it's not very useful...) DoNppFileBeforeLoad(); return; case (uint)NppNotif.NPPN_FILEOPENED: // on file opened OnNppFileOpened(); return; case (uint)NppNotif.NPPN_FILEBEFORECLOSE: // on file closed OnNppFileBeforeClose(); return; } // only do extra stuff if we are in a progress file if (!CurrentFileAllowed) return; #region extra switch (code) { case (uint)NppNotif.NPPN_FILEBEFORESAVE: // on file saved OnNppFileBeforeSaved(); return; case (uint)NppNotif.NPPN_SHORTCUTREMAPPED: // notify plugins that plugin command shortcut is remapped //NppMenu.ShortcutsUpdated((int) nc.nmhdr.idFrom, (ShortcutKey) Marshal.PtrToStructure(nc.nmhdr.hwndFrom, typeof (ShortcutKey))); return; // -------------------------------------------------------- // Scintilla message // -------------------------------------------------------- case (uint) SciNotif.SCN_CHARADDED: // called each time the user add a char in the current scintilla OnSciCharTyped((char) nc.ch); return; case (uint) SciNotif.SCN_UPDATEUI: OnSciUpdateUi(nc); return; case (uint) SciNotif.SCN_MODIFIED: OnSciModified(nc); 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 //Style.Colorize(Npp.GetSylingNeededStartPos(), nc.position); return; case (uint) SciNotif.SCN_MARGINCLICK: // called each time the user click on a margin 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 OnSciDwellStart(); return; case (uint) SciNotif.SCN_DWELLEND: // when he moves his cursor OnSciDwellEnd(); return; } #endregion } catch (Exception e) { ErrorHandler.ShowErrors(e, "Error in beNotified : code = " + nc.nmhdr.code); } }
/// <summary> /// Updates the line info when inserting text /// </summary> /// <param name="scn"></param> private void OnInsertedText(SCNotification scn) { var startLine = SciLineFromPosition(scn.position); if (scn.linesAdded == 0) { var insCharLenght = GetCharCount(scn.position, scn.length); SetHoleInLine(startLine, insCharLenght); } else { var startCharPos = CharPositionFromLine(startLine); var lineByteStart = SciPositionFromLine(startLine); var lineByteLength = SciLineLength(startLine); var lineCharLenght = GetCharCount(lineByteStart, lineByteLength); var insCharLenght = lineCharLenght - LineCharLength(startLine); FillTheHole(); for (int i = 0; i < scn.linesAdded; i++) { startCharPos += lineCharLenght; var line = startLine + i + 1; lineByteStart += lineByteLength; lineByteLength = SciLineLength(line); lineCharLenght = GetCharCount(lineByteStart, lineByteLength); insCharLenght += lineCharLenght; _linesList.Insert(line, startCharPos); } SetHoleInLine(startLine + scn.linesAdded, insCharLenght); FillTheHole(); // We should not have a null lenght, but we actually can : // when a file is modified outside npp, npp suggests to reload it, a modified notification is sent // but is it sent BEFORE the text is actually put into scintilla! So what we do here doesn't work at all // so in that case, we need to refresh the info when the text is acutally inserted, that is after updateui if (TextLength == 0) { Plug.ActionsAfterUpdateUi.Enqueue(Reset); } } }
/// <summary> /// updates the line info when deleting text /// </summary> /// <param name="scn"></param> private void OnDeletedText(SCNotification scn) { var startLine = SciLineFromPosition(scn.position); if (scn.linesAdded == 0) { var delCharLenght = GetCharCount(scn.text, scn.length, _lastEncoding); SetHoleInLine(startLine, -delCharLenght); } else { var lineByteStart = SciPositionFromLine(startLine); var lineByteLength = SciLineLength(startLine); var delCharLenght = -(GetCharCount(lineByteStart, lineByteLength) - LineCharLength(startLine)); FillTheHole(); for (int i = 0; i < -scn.linesAdded; i++) { delCharLenght += LineCharLength(startLine + 1); _linesList.RemoveAt(startLine + 1); } SetHoleInLine(startLine, -delCharLenght); FillTheHole(); } }
/// <summary> /// Simulates the insertion of the whole text, use this to reset the lines info /// (when switching document for instance) /// </summary> internal void Reset() { _lastEncoding = Npp.Encoding; _oneByteCharEncoding = _lastEncoding.Equals(Encoding.Default); // bypass the hard work for simple encoding if (_oneByteCharEncoding) return; _linesList = new GapBuffer<int> { 0, 0 }; var scn = new SCNotification { linesAdded = SciGetLineCount() - 1, position = 0, length = SciGetLength() }; scn.text = Npp.Sci.Send(SciMsg.SCI_GETRANGEPOINTER, new IntPtr(scn.position), new IntPtr(scn.length)); OnInsertedText(scn); }
/// <summary> /// When receiving a modification notification by scintilla /// </summary> public void OnScnModified(SCNotification scn, bool isInsertion) { _lastEncoding = Npp.Encoding; _oneByteCharEncoding = _lastEncoding.Equals(Encoding.Default); // bypass the hard work for simple encoding if (_oneByteCharEncoding) return; if (isInsertion) { OnInsertedText(scn); } else { OnDeletedText(scn); } }