I've had a need to add search & replace capabilities, here's my efforts...
(Uses PB's PCRE and extends that with back-reference replacing.)
Save this alongside the GoScintilla.pbi as GoScintilla_Regex.pbi
Code: Select all
XIncludeFile "GoScintilla.pbi"
CompilerIf Defined(pcre_exec,#PB_Procedure) = 0
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
ImportC ""
pcre_exec(*pcre, *extra, subject, length, startoffset, options, *ovector, ovecsize) As "pb_pcre_exec"
EndImport
CompilerElse
ImportC ""
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
pcre_exec(*pcre,*extra,subject,length,startoffset,options,*ovector,ovecsize) As "pb_pcre_exec"
CompilerElse
pcre_exec(*pcre,*extra,subject,length,startoffset,options,*ovector,ovecsize) As "_pb_pcre_exec"
CompilerEndIf
EndImport
CompilerEndIf
CompilerEndIf
#PCRE_CASELESS = $00000001
#PCRE_MULTILINE = $00000002 ; Same as #PB_RegularExpression_MultiLine
#PCRE_DOTALL = $00000004 ; Same as #PB_RegularExpression_DotAll
#PCRE_EXTENDED = $00000008 ; Same as #PB_RegularExpression_Extended
#PCRE_UNGREEDY = $00000200
#PCRE_NEWLINE_CR = $00100000
#PCRE_NEWLINE_LF = $00200000
#PCRE_NEWLINE_CRLF = $00300000
#PCRE_NEWLINE_ANY = $00400000
#PCRE_NEWLINE_ANYCRLF = $00500000 ; Same as #PB_RegularExpression_AnyNewLine
; Selects the first match of regex search from given position.
; Also scrolls that match into view
; returns position of match if found or -1 if not found
Procedure GOSCI_RegexSearch(id, text$, pos = 0, flags = 0)
Protected *Buffer, length, regex_h, result=-1
Protected Dim ov(2)
If IsGadget(id) And GadgetType(id) = #PB_GadgetType_Scintilla
If text$ = "" : ProcedureReturn -1 : EndIf
regex_h = CreateRegularExpression(#PB_Any,text$,flags)
If regex_h
length = ScintillaSendMessage(id,#SCI_GETLENGTH)
*Buffer = AllocateMemory(length)
If *Buffer
ScintillaSendMessage(id, #SCI_GETTEXT, length, *Buffer)
pcre_exec(PeekI(regex_h), 0, *Buffer, length, pos, 0, @ov(), ArraySize(ov()))
If ov(0) > -1
ScintillaSendMessage(id, #SCI_SETSEL, ov(0), ov(1))
result = ov(0)
EndIf
FreeMemory(*Buffer)
EndIf
FreeRegularExpression(regex_h)
EndIf
EndIf
ProcedureReturn result
EndProcedure
; Replaces All occurences of search text with replace text
Procedure GOSCI_RegexReplaceAll(id, searchtext$, replacetext$, flags=0, clearUndoStack=#False)
Protected text$
Protected Dim ov(30)
Protected utf8Len, subBuf$, reg_rep$, i
If IsGadget(id) And GadgetType(id) = #PB_GadgetType_Scintilla
If searchtext$ = "" : ProcedureReturn -1 : EndIf
*regex_h.Integer = CreateRegularExpression(#PB_Any, searchtext$, flags)
If *regex_h
text$ = GOSCI_GetText(id)
Repeat
utf8Len = StringByteLength(text$, #PB_UTF8)
subBuf$ = Space(utf8Len+2)
PokeS(@subBuf$, text$, -1, #PB_UTF8)
If pcre_exec(*regex_h\i, 0, @subBuf$, utf8Len, ov(1), 0, @ov(), ArraySize(ov())) < 0
Break
EndIf
reg_rep$=replacetext$
For i = 1 To 9
If FindString(reg_rep$,"\"+Str(i),1)
reg_rep$=ReplaceString(reg_rep$,"\"+Str(i),PeekS(@subBuf$+ov(i*2),ov(i*2+1)-ov(i*2), #PB_UTF8))
EndIf
Next
text$ = PeekS(@subBuf$, ov(0), #PB_UTF8) + reg_rep$ + PeekS(@subBuf$+ov(1), utf8Len-ov(1), #PB_UTF8)
ForEver
FreeRegularExpression(*regex_h)
EndIf
GOSCI_SetText(id, text$, clearUndoStack)
EndIf
ProcedureReturn result
EndProcedure
Procedure GOSCI_RegexReplaceInSelected(id, searchtext$, replacetext$, flags=0, replace_all=#False)
Protected text$
Protected Dim ov(30)
Protected utf8Len, subBuf$, reg_rep$, i
If IsGadget(id) And GadgetType(id) = #PB_GadgetType_Scintilla
If searchtext$ = "" : ProcedureReturn -1 : EndIf
*regex_h.Integer = CreateRegularExpression(#PB_Any, searchtext$, flags)
If *regex_h
text$ = GOSCI_GetSelectedText(id)
Repeat
utf8Len = StringByteLength(text$, #PB_UTF8)
subBuf$ = Space(utf8Len+2)
PokeS(@subBuf$, text$, -1, #PB_UTF8)
pcre_exec(*regex_h\i, 0, @subBuf$, utf8Len, ov(1), 0, @ov(), ArraySize(ov()))
If ov(0)>-1
reg_rep$=replacetext$
For i = 1 To 9
If FindString(reg_rep$,"\"+Str(i),1)
reg_rep$=ReplaceString(reg_rep$,"\"+Str(i),PeekS(@subBuf$+ov(i*2),ov(i*2+1)-ov(i*2), #PB_UTF8))
EndIf
Next
text$ = PeekS(@subBuf$, ov(0), #PB_UTF8) + reg_rep$ + PeekS(@subBuf$+ov(1), utf8Len-ov(1), #PB_UTF8)
Else
Break
EndIf
If replace_all=#False : Break : EndIf
ForEver
GOSCI_ReplaceSelectedText(id, text$)
FreeRegularExpression(*regex_h)
EndIf
EndIf
ProcedureReturn result
EndProcedure
Then for a test, here's an example, save it again alongside the GoScintilla.pbi or add an include path as in other provided examples and save alongside them.
Code: Select all
XIncludeFile "GoScintilla.pbi"
XIncludeFile "GoScintilla_Regex.pbi"
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
InitScintilla()
CompilerEndIf
Enumeration
#g_sci
#g_reset
#g_search
#g_replace
#g_replaceALL
#g_search2
#g_replace2
EndEnumeration
If OpenWindow(0,0,0,650,270,"GO_Scintilla Regex Search + Replace test.",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
RemoveKeyboardShortcut(0, #PB_Shortcut_Tab) ;Required for the tab key to function correctly when the Scintilla control has the focus.
GOSCI_Create(#g_sci, 10, 40, 630, 220, 0, #GOSCI_AUTOSIZELINENUMBERSMARGIN)
GOSCI_SetAttribute(#g_sci, #GOSCI_LINENUMBERAUTOSIZEPADDING, 10)
GOSCI_SetAttribute(#g_sci, #GOSCI_WRAPLINES, #True)
GOSCI_SetColor(#g_sci, #GOSCI_CARETLINEBACKCOLOR, $A0FFFF)
GOSCI_SetFont(#g_sci, "Courier New", 12)
GOSCI_SetTabs(#g_sci, 2)
ButtonGadget(#g_reset, 5, 5, 90, 30, "Reset")
ButtonGadget(#g_search, 105, 5, 90, 30, "Search 1")
ButtonGadget(#g_replace, 205, 5, 90, 30, "Replace 1")
ButtonGadget(#g_replaceALL, 305, 5, 90, 30, "All")
ButtonGadget(#g_search2, 405, 5, 90, 30, "Search 2")
ButtonGadget(#g_replace2, 505, 5, 90, 30, "Replace 2")
flags=#PCRE_MULTILINE|#PCRE_NEWLINE_ANYCRLF|#PCRE_DOTALL|#PCRE_CASELESS
test.s = "This is regex powered searching."+#CRLF$
test.s + "This is his whisper."+#CRLF$+"Also handles"+#CRLF$+"newlines in search."+#CRLF$
test.s + "Search 1 searches for the word 'regex' and scrolls into view if needed."+#CRLF$
test.s + "Replace 1 replaces the selected text with 'super'."+#CRLF$
test.s + "All replaces all occurences of 'is' which are followed with whitespace, with '_is_'."+#CRLF$
test.s + "Search 2 searches for lines that end with lowercase letter and begin the next line with lowercase as well."+#CRLF$
test.s + "Replace 2 searches the selected text and does same search as for Search 2 and replaces the linebreak with a space."
GOSCI_SetText(#g_sci,test)
Repeat
ev=WaitWindowEvent()
Select ev
Case #PB_Event_Gadget
EvG=EventGadget()
Select EvG
Case #g_reset
GOSCI_SetText(#g_sci,test)
Case #g_search
search.s = "regex"
GOSCI_RegexSearch(#g_sci,search,0,flags)
Case #g_replace
If GOSCI_GetSelectedText(#g_sci)
GOSCI_ReplaceSelectedText(#g_sci,"super",#True)
EndIf
Case #g_replaceALL
search.s = "(is)(?=\s)"
replace.s= "_\1_"
GOSCI_RegexReplaceAll(#g_sci,search,replace,flags)
Case #g_search2
search.s = "([a-z])\R([a-z])"
GOSCI_RegexSearch(#g_sci,search,0,flags)
Case #g_replace2
search.s = "([a-z])\R([a-z])"
replace.s= "\1 \2"
GOSCI_RegexReplaceInSelected(#g_sci,search,replace,flags)
EndSelect
Case #PB_Event_CloseWindow
QUIT=#True
EndSelect
Until QUIT=#True
EndIf
I tried to copy srod' layout for the procedures.
Please feel free to scrutinise/criticise/adapt as you see fit.
CompilerIf's at top may need tweaking for 64bit and MacOS.
This has been tried on WinXP, Win7 and Xubuntu 11.10 - all 32bit.
Edit: adjusted code - thanks srod.
Edit2: changed GOSCI_Search() to GOSCI_RegexSearch() : - avoid clash with tssoft's GoSCI_Search()