Code: Select all
; Все плаги сейчас в юникоде, поэтому этот исходник в юникоде
EnableExplicit
Structure NppData Align #PB_Structure_AlignC
*_nppHandle
*_scintillaMainHandle
*_scintillaSecondHandle
EndStructure
Structure ShortcutKey Align #PB_Structure_AlignC
_isCtrl.b
_isAlt.b
_isShift.b
_key.b
EndStructure
Structure FuncItem Align #PB_Structure_AlignC
_itemName.s{64}
*_pFunc
_cmdID.l ; тут я поменял i на l, иначе в x64 не работает
_init2Check.b
*_pShortcutKey.ShortcutKey
EndStructure
; ==================================
; 2 Обязательные процедуры DLL (AttachProcess, DetachProcess)
; ==================================
Declare item1()
Declare item2()
Declare itemError()
Declare NppMenuCommand(command)
Declare GetCurrentScintilla()
Declare ScintillaMsg(*point, msg, param1 = 0, param2 = 0)
; Константы NPP для вызовов функций
; Описание команд и уведомлений NPP http://docs.notepad-plus-plus.org/index.php/Messages_And_Notifications
; числовые значения констант NPP https://github.com/editorconfig/editorconfig-notepad-plus-plus/blob/master/src/Notepad_plus_msgs.hpp
; числовые значения констант Scintilla https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/scintilla/include/Scintilla.h
XIncludeFile "NNP_Const.pb"
;{
; Константы для получения экземпляра Scintilla
; #WM_USER = 1024
; #NPPMSG = #WM_USER + 1000
; #NPPM_GETCURRENTSCINTILLA = #NPPMSG + 4 ; для получения экземпляра Scintilla в режиме отображения сразу двух документов
; #NPPM_SETMENUITEMCHECK = #NPPMSG + 40 ; для установки / снятия галки с пункта меню
; Константы вызова меню
; #NPPM_MENUCOMMAND = 2024 + 48
; #IDM = 40000
; #IDM_SEARCH = (#IDM + 3000)
; #IDM_SEARCH_TOGGLE_BOOKMARK = (#IDM_SEARCH + 5) ; Переключить закладку в строке
; #IDM_SEARCH_REPLACE = (#IDM_SEARCH + 3) ; показать окно поиска изамены
; Константы чтобы получить имя файла
; #FILE_NAME = 3
; #RUNCOMMAND_USER = (#WM_USER + 3000)
; #NPPM_GETFILENAME = #RUNCOMMAND_USER + #FILE_NAME
; Константы уведомления
; #NPPN_FIRST = 1000
; #NPPN_BUFFERACTIVATED = (#NPPN_FIRST + 10) ; пполезное уведомление при смене вкладки
; #NPPN_READY = (#NPPN_FIRST + 1) ; уведомление что NPP и плагины загружены и можно обрабатывать уведомления
;}
; глобальные константы
Global *sciptr, post_processing = 1
; *sciptr - указатель Scintilla текущего документа
Global NppData.NppData ; создаём структуру NppData (3 дескриптора, NPP, Scintilla1, Scintilla2)
; Global PluginName.s = "Plugin name" ; Имя плагина, отображается в меню плагинов, см. getName() ниже
PrototypeC ScintillaDirect(sciptr, msg, param1 = 0, param2 = 0)
Global Scintilla.ScintillaDirect = 0
; Начало блока: фатальная ошибка
; Это чтобы при фатальных ошибках выводить осмысленное сообщение с указанием строки, файла, типа ошибки
; Добавилось 4 Кб к DLL (зависит от числа команд/строк в исходнике), по крайней мере на время теста полезно.
Procedure FatalError()
Protected Result.s
Result = "Ошибка программы"
; Result = "Program error"
CompilerIf #PB_Compiler_LineNumbering
Result + " в строке " + ErrorLine() + ", файла: " + GetFilePart(ErrorFile())
; Result + " in line " + ErrorLine() + ", of file: " + GetFilePart(ErrorFile())
CompilerElse
CompilerError "Включите в настройках компилятора поддержку OnError"
; CompilerError "Turn on compiler support OnError"
CompilerEndIf
Result + Chr(10) + Chr(10) + "Ошибка типа: " + Chr(34) + ErrorMessage() + Chr(34)
; Result + Chr(10) + Chr(10) + "Type Error: " + Chr(34) + ErrorMessage() + Chr(34)
MessageRequester("Ошибка программы!", Result, #MB_OK | #MB_ICONERROR)
; MessageRequester("Program error!", Result, #MB_OK | #MB_ICONERROR)
EndProcedure
; Конец блока: фатальная ошибка
ProcedureDLL AttachProcess(Instance)
; << Когда Notepad++ задействовал этот плагин при запуске Notepad++ >>
; Ваш код инициализации здесь
OnErrorCall(@FatalError()) ; вызывает процедуру FatalError(), если произойдёт ошибка. Отсюда начинаем использовать её.
; If Scintilla
Global Dim FuncsArray.FuncItem(2) ; массив FuncsArray по структуре FuncItem, являющейся пунктами меню
With FuncsArray(0) ; 1) задаём элементы структуры, это будет пункт меню с горячей клавишей (которая не работает)
\_itemName = "item 1" ; Задаём имя пункта, отображается в меню плагина, дочерний к "Plugin name"
\_pFunc = @item1() ; Задаём имя процедуры item1, которая будет выполнятся при клике на пункте
\_pShortcutKey = AllocateStructure(ShortcutKey) ; выделяем память для структуры горячей клавиши
\_pShortcutKey\_isCtrl = #True ; Будет ли нажат Ctrl (#True / #False)
\_pShortcutKey\_isShift = #True ; Будет ли нажат Shift (#True / #False)
\_pShortcutKey\_isAlt = #True ; Будет ли нажат Alt (#True / #False)
\_pShortcutKey\_key = #VK_NEXT ; Собственно клавиша
EndWith
; Делаем аналог предыдущего пункта
With FuncsArray(1)
\_itemName = "item 2" ; Задаём имя 2-го пункта
\_pFunc = @item2() ; Задаём имя процедуры item2 для 2-го пункта
; \_init2Check = #True ; Здесь задаём будет ли элемент отмечен галкой,
; \_init2Check = #False ; но это не значит, что изменение этого поля структуры будет влиять, см. ниже NPPM_SETMENUITEMCHECK
; клавиши не создаём, они всё равно не работают
EndWith
; With FuncsArray(2) ; Пункт-разделитель, учитывайте индексы
; \_itemName = ""
; EndWith
; Пунктов можно делать сколько угодно, просто добавляем индекс к item, к элементу массива, и к размеру создаваемого массива (Dim)
; Else ; если не получили функцию Scintilla, то добавляем один пункт в виде сообщения об ошибке
; Global Dim FuncsArray.FuncItem(1)
; With FuncsArray(0)
; \_itemName = "Error"
; \_pFunc = @itemError()
; EndWith
; EndIf
EndProcedure
ProcedureDLL DetachProcess(Instance)
; << Когда Notepad++ удаляет этот плагин >>
; Ваш код очистки здесь
Protected i
For i = 0 To ArraySize(FuncsArray())
FreeStructure(FuncsArray(i)\_pShortcutKey)
Next
EndProcedure
; ==================================
; 5 Обязательные процедуры Notepad++
; ==================================
; NPP спрашивает, является ли плагин в юникоде, возвращаем "ДА"
ProcedureCDLL.i isUnicode()
ProcedureReturn #PB_Compiler_Unicode
EndProcedure
; NPP спрашивает имя плагина
ProcedureCDLL.s getName()
; ProcedureReturn PluginName
ProcedureReturn "Plugin name" ; передаём имя плагина явно, чтобы не плодить переменных
EndProcedure
; NPP спрашивает, элементы меню, чтобы встроить их в меню "Плагины"
ProcedureCDLL.i getFuncsArray(*FuncsArraySize.Integer)
*FuncsArraySize\i = ArraySize(FuncsArray()) ; Возвращаем ему размер массива структур пунктов меню
ProcedureReturn @FuncsArray() ; Возвращаем указатель на массив структур пунктов меню
EndProcedure
; Компиляция взависимости от x86 или x64
; setInfo выполняется при запуске программы и передаёт плагинам дескрипторы NPP, Scintilla1, Scintilla2
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
ProcedureCDLL setInfo(*NppHandle, *ScintillaMainHandle, *ScintillaSecondHandle)
; Здесь мы заполняем элементы нашей структуры NppData, то есть получаем от NPP дескприторы NPP, Scintilla1, Scintilla2
NppData\_nppHandle = *NppHandle
NppData\_scintillaMainHandle = *ScintillaMainHandle
NppData\_scintillaSecondHandle = *ScintillaSecondHandle
; получаем указатель на функцию Scintilla_DirectFunction
Scintilla = SendMessage_(NppData\_scintillaMainHandle, #SCI_GETDIRECTFUNCTION, 0, 0)
; << Когда инфа Notepad++ изменилась >>
; Ваш код здесь
EndProcedure
CompilerElse ; иначе для x64
ProcedureCDLL setInfo(*Npp.NppData)
CopyStructure(*Npp, NppData, NppData) ; копируем структуру переданную из NPP в нашу
Scintilla = SendMessage_(NppData\_scintillaMainHandle, #SCI_GETDIRECTFUNCTION, 0, 0)
; << Когда инфа Notepad++ изменилась >>
; Ваш код здесь
EndProcedure
CompilerEndIf
; УВЕДОМЛЕНИЯ, что мы получаем в структуре SCNotification
; Переписываем данные из структуры в переменные
; code= *SCNotification.SCNotification\nmhdr\code
; pos= *SCNotification.SCNotification\Position
; ch= *SCNotification.SCNotification\ch
; modificationType= *SCNotification.SCNotification\modifiers
; text= *SCNotification.SCNotification\text
; Length= *SCNotification.SCNotification\length
; linesAdded= *SCNotification.SCNotification\linesAdded
; message= *SCNotification.SCNotification\message
; wParam= *SCNotification.SCNotification\wParam
; lParam= *SCNotification.SCNotification\lParam
; line= *SCNotification.SCNotification\line
; foldLevelNow= *SCNotification.SCNotification\foldLevelNow
; foldLevelPrev= *SCNotification.SCNotification\foldLevelPrev
; margin= *SCNotification.SCNotification\margin
; listType= *SCNotification.SCNotification\listType
; x= *SCNotification.SCNotification\x
; y= *SCNotification.SCNotification\y
ProcedureCDLL beNotified(*SCNotification.SCNotification)
Protected i
; Если вы не используете уведомления, а только пункты меню, просто удалите конструкцию от "With *SCNotification" до "EndWith"
; << Когда было получено уведомление scintilla Notepad++ >>
; Ваш код здесь
With *SCNotification
Select \nmhdr\code
; Case #NPPN_READY ; Notepad++ загружен, теперь можно обрабатывать уведомления
; post_processing = 0 ; флаг полезен если используются уведомления, чтобы они не работали когда NPP в процессе запуска
Case #NPPN_BUFFERACTIVATED ; реагируем на смену вкладки
*sciptr = SendMessage_(GetCurrentScintilla(), #SCI_GETDIRECTPOINTER, 0, 0) ; дескриптор текущего экземпляра scintilla
; мы можем получать *sciptr при выполнении пункта меню, а не запрашивать его при смене вкладки, это зависит как часто происходит запрос
; Case #SCN_SAVEPOINTLEFT ; точка сохранения оставлена, файл требует сохранения
; flag_not_save = 1
; Case #SCN_SAVEPOINTREACHED ; произошло сохранение документа
; flag_not_save = 0
; Case #SCN_MODIFIED ; реакция на модификацию документа (плаг пометки изменений)
; Select #True
; Case Bool(\modificationType & 1) ; если в типе модификации есть флаг вставки SC_MOD_INSERTTEXT, то (ввод символа или Ctrl+V)
; If post_processing ; пример запрета уведомления на запуске
; ProcedureReturn
; EndIf
; Case Bool(\modificationType & 2) ; если в типе модификации есть флаг удаления SC_MOD_DELETETEXT, то (удаление символа или выделенного)
; If post_processing ; пример запрета уведомления на запуске
; ProcedureReturn
; EndIf
; EndSelect
; Case #NPPN_LANGCHANGED ; изменить синтаксис документа, например с AutoIt3 на PureBasic
; SetWindowTitle(#Window_0, GetExt())
; Case #SCN_CHARADDED ; реакция на ввод символа (плаг автозавершение)
; Select \ch
; Case 'a' To 'z', 'A' To 'Z', '0' To '9', '_'
; SetWindowTitle(#Window_0 , Chr(\ch))
; Default
; SetWindowTitle(#Window_0 , Chr(\ch))
; EndSelect
EndSelect
; Придумать вывод в консоль
; Что мы можем получить в уведомлении
; LineStart = ScintillaMsg(*sciptr, #SCI_LINEFROMPOSITION, \position) ; Получаем номер строки начала вставки
; LineEnd = ScintillaMsg(*sciptr, #SCI_LINEFROMPOSITION, \position + \Length) ; Получаем номер строки конец вставки
; LengthDoc = ScintillaMsg(*sciptr, #SCI_GETLENGTH) ; длина текста
; CountLine = ScintillaMsg(*sciptr, #SCI_GETLINECOUNT) ; возвращает количество строк
; For i = 0 To CountLine
; выполнить пошаговые операции со строками
; Next
EndWith
EndProcedure
ProcedureCDLL.i messageProc(Message, wParam, lParam)
; << Когда было получено windows-сообщение Notepad++ >>
; Ваш код здесь
ProcedureReturn #True
EndProcedure
; ==================================
; Ещё несколько системных процедур
; ==================================
; Это оболочка функции Scintilla, полученной из SciLexer.dll,
; проверяет, что существует указатель функции и указатель экземляра
; А также передаёт по умолчанию последние два параметра если пользователь их не задал явно.
; !!! Если заранее сделать проверку Scintilla на запуске и учёт обязательных 4-х параметров, то от оболочки можно избавиться !!!
Procedure ScintillaMsg(*point, msg, param1 = 0, param2 = 0)
If Scintilla And *point
ProcedureReturn Scintilla(*point, msg, param1, param2) ; Scintilla - прототип функции Scintilla_DirectFunction
Else
ProcedureReturn 0
EndIf
EndProcedure
; Процедура для определения текущего окна Scintilla, одного из двух
Procedure GetCurrentScintilla()
Protected instance_sci
SendMessage_(NppData\_nppHandle, #NPPM_GETCURRENTSCINTILLA, 0, @instance_sci)
If instance_sci
ProcedureReturn NppData\_scintillaSecondHandle
Else
ProcedureReturn NppData\_scintillaMainHandle
EndIf
EndProcedure
; любой пункт меню можно выполнить используя константы #IDM_...
Procedure NppMenuCommand(IDM_COMMAND)
SendMessage_(NppData\_nppHandle, #NPPM_MENUCOMMAND, 0, IDM_COMMAND)
EndProcedure
; ==================================
; Ваши процедуры плагина
; ==================================
Procedure item1()
If post_processing
post_processing = 0
SendMessage_(NppData\_nppHandle, #NPPM_SETMENUITEMCHECK, FuncsArray(0)\_cmdID, 1) ; Пример переключения галки пункта меню
Else
post_processing = 1
SendMessage_(NppData\_nppHandle, #NPPM_SETMENUITEMCHECK, FuncsArray(0)\_cmdID, 0)
EndIf
EndProcedure
Procedure item2()
; Protected
ScintillaMsg(*sciptr, #SCI_GOTOLINE, 1)
NppMenuCommand(#IDM_SEARCH_TOGGLE_BOOKMARK)
ScintillaMsg(*sciptr, #SCI_GOTOPOS, 1)
EndProcedure
; Procedure itemError()
; MessageRequester("Ошибка", "Не удалось получить функцию", #MB_OK | #MB_ICONERROR)
; MessageRequester("Error", "Failed to get a function", #MB_OK | #MB_ICONERROR)
; EndProcedure