Scintilla find/replace

Just starting out? Need help? Post your questions and find answers here.
User avatar
Crusiatus Black
Enthusiast
Enthusiast
Posts: 389
Joined: Mon May 12, 2008 1:25 pm
Location: The Netherlands
Contact:

Scintilla find/replace

Post by Crusiatus Black »

Hey all,

Me again, asking for help and info once again.

I'm trying to find info regarding implementing find/replace features in Scintilla, but I can't find
any stuff that explains to me how I can implement this in PureBasic. I would like to code a
dialog similar to the one in the PureBasic IDE, coding the window is easy, but the step of
actually finding / selecting and replacing content in scintilla is unclear to me.

Does anyone have some pointers where precisely I should look, and perhaps some example
code?

Thanks!
Image
Bas Groothedde,
Imagine Programming

I live in a philosophical paradoxal randome filled with enigma's!
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Scintilla find/replace

Post by Tenaja »

http://www.scintilla.org/
has everything you need. The Documentation page describes all of the commands, and the source code for the SciTe editor is also available there.
You might also consider checking out GoScintilla on this forum; SRod has done a great job of making a library that converts many lines into a short command.

Edit: there are two Search methods with Scintilla; one repositions the screen, and the other does not. Use the appropriate one for your task.
User avatar
falsam
Enthusiast
Enthusiast
Posts: 632
Joined: Wed Sep 21, 2011 9:11 am
Location: France
Contact:

Re: Scintilla find/replace

Post by falsam »

Crusiatus Black wrote:Does anyone have some pointers where precisely I should look, and perhaps some examplecode? Thanks!
Minimalist code include 2 procedures.
ScintillaStringFind(StringFind.s) and ScintillaStringReplace(StringFind.s, StringReplace.s)

Short Key
Ctrl + F : Open Search Replace Dialog
F3 : When Open Search Replace Dialog is close, to continue the search.

Code: Select all

; Scintilla : Search Replace Exemple

EnableExplicit

Enumeration
  #Mainform
  #Editor
  
  #StringFindForm
	
	#StringFind
	#StringFindCheck
	#StringReplace
	#Btn_StringFindNext
	#Btn_StringFindReplace
	#Btn_StringFindEnd
        #Kbd_CtrlF  ;Shortcut Find / replace
	#Kbd_F3     ;Shortcut Next string
	#Kbd_Return 

EndEnumeration

Define.l Event, WEvent, MEvent, GEvent, TEvent

Global WindowStyle.i=#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered

;Find replace
Global StringFind.s, StringReplace.s

;Indentation
Global SciPos.l, SciLine.l, SciCol.l, SciIndent.l

; Find String
Procedure ScintillaStringFind(StringFind.s)
  Protected Current.l, start.l, Anchor.l
    If StringFind <> ""
      Current = ScintillaSendMessage(#Editor, #SCI_GETCURRENTPOS)
      ScintillaSendMessage(#Editor, #SCI_SETANCHOR, Current)
      ScintillaSendMessage(#Editor, #SCI_SEARCHANCHOR)
      Start = ScintillaSendMessage(#Editor, #SCI_SEARCHNEXT, 0, @StringFind)
      If  Start<> -1
        anchor = ScintillaSendMessage(#Editor, #SCI_GETANCHOR)
        ScintillaSendMessage(#Editor, #SCI_SETSEL, start, anchor)
      Else
        MessageRequester("Find string", "No more matching")
      EndIf
    EndIf
    
EndProcedure



; Find Replace string
Procedure  ScintillaStringReplace(StringFind.s, StringReplace.s)
  Protected StringSel.s 
  
  ;Storing the selected word
  ScintillaSendMessage(#Editor, #SCI_COPY)
  StringSel=GetClipboardText()
  
  If LCase(StringSel)=LCase(StringFind)
    SetClipboardText(StringReplace)
    ScintillaSendMessage(#Editor, #SCI_PASTE)
    
    ;Find the next occurrence
    ScintillaStringFind(StringFind)
  EndIf
  

EndProcedure


; Show find/replace string dialog
Procedure Open_StringFindForm()
	If OpenWindow(#StringFindForm,0,0,455,195,"Find/Replace",#PB_Window_Tool|#PB_Window_WindowCentered,WindowID(#Mainform))
	  TextGadget(#PB_Any,30,21,85,20,"Find")
	  ComboBoxGadget(#StringFind,130,18,310,23,#PB_ComboBox_Editable)
	  
	  CheckBoxGadget(#StringFindCheck,15,60,105,20,"Replace by")
		ComboBoxGadget(#StringReplace,130,59,310,23,#PB_ComboBox_Editable)
		
		ButtonGadget(#Btn_StringFindNext,20,150,125,20,"Next String")
		ButtonGadget(#Btn_StringFindReplace,160,150,80,20,"Find (Replace)")
		ButtonGadget(#Btn_StringFindEnd,360,150,80,20,"Close")
		
		DisableGadget(#StringReplace, #True)
		DisableGadget(#Btn_StringFindReplace, #True)
		   
		SetActiveGadget(#StringFind)
		
		AddKeyboardShortcut(#StringFindForm, #PB_Shortcut_Return, #Kbd_Return) ;Find String
	EndIf
EndProcedure

; Scintilla Callback
;
; CallBack To receive the events of Scintilla gadget
; scinotify * pointer to a structure containing the information on the event:
; See the bottom of this page http://www.scintilla.org/ScintillaDoc.html
;
; -Knowing the current cursor position and correctly position
;  after having press the Enter key
Procedure ScintillaCallBack(Gadget, *scinotify.SCNotification)
  ; Enter key is used
  If *scinotify\ch=13
    
    ;New line: Cursor on the indentation of the previous line.
    ScintillaSendMessage(Gadget, #SCI_SETLINEINDENTATION, SciLIne+1, SciIndent)
    If SciIndent=0 
      SciPos=SciPos+2
    EndIf
   
    ScintillaSendMessage(Gadget, #SCI_GOTOPOS, SciPos+SciIndent)

  EndIf
  
  ;Position in the chain scintilla
  SciPos = ScintillaSendMessage(Gadget, #SCI_GETANCHOR)
  
  ;Line from position
  SciLine = ScintillaSendMessage(Gadget, #SCI_LINEFROMPOSITION, SciPos)
  
  ;Column from position
  SciCol = ScintillaSendMessage(Gadget, #SCI_GETCOLUMN, SciPos)
  
  ;Determination de l'indentation
  SciIndent = ScintillaSendMessage(Gadget, #SCI_GETLINEINDENTATION, SciLine)  
EndProcedure


;Init scintilla properties (minimalist)
Procedure ScintillaSetProperties(Gadget)
 
 ScintillaSendMessage(Gadget,  #SCI_SETLEXER, 0); No lexer
  
 ScintillaSendMessage(Gadget, #SCI_STYLESETFONT, #STYLE_DEFAULT,@"Arial") ;Police
 ScintillaSendMessage(Gadget, #SCI_STYLESETSIZE, #STYLE_DEFAULT, 12) ;Size
 ScintillaSendMessage(Gadget, #SCI_STYLECLEARALL)
  
 ScintillaSendMessage(Gadget, #SCI_SETCARETLINEBACK, RGB(245, 245, 220));Line Active BackColor
 ScintillaSendMessage(Gadget, #SCI_SETCARETLINEVISIBLE, #True) ;Cursor Yes
 ScintillaSendMessage(gadget, #SCI_SETCARETWIDTH, 3) ;Cursor Size
 
 ScintillaSendMessage(Gadget, #SCI_SETUSETABS, #False) ;User tabs replace by space
 ScintillaSendMessage(Gadget, #SCI_SETINDENT, 8) ; Number spaces
        
EndProcedure


;Mainform
Procedure Open_MainForm()
  OpenWindow(#Mainform, 0, 0, 800, 600, "New Form", WindowStyle)
  ScintillaGadget(#Editor, 10, 10, 780, 580, @ScintillaCallBack())
  ScintillaSetProperties(#Editor)
  
  ;Init Shortcut  
  RemoveKeyboardShortcut(#Mainform, #PB_Shortcut_Tab)
  AddKeyboardShortcut(#Mainform, #PB_Shortcut_F|#PB_Shortcut_Control, #Kbd_CtrlF)
  AddKeyboardShortcut(#Mainform, #PB_Shortcut_F3, #Kbd_F3)
  
  SetActiveGadget(#Editor)

EndProcedure

Procedure Start()
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    InitScintilla()
  CompilerEndIf

  Open_MainForm()
EndProcedure

start()

Repeat
  Event  = WaitWindowEvent(10)
  WEvent = EventWindow()
  MEvent = EventMenu()
  GEvent = EventGadget()
  TEvent = EventType()
  Select Event
    Case #PB_Event_Menu
      Select MEvent
        Case #Kbd_CtrlF
          Open_StringFindForm()
          
        Case #Kbd_F3 
          ScintillaStringFind(StringFind)
          
        Case #Kbd_Return
          Select WEvent 
            Case #StringFindForm
              ScintillaStringFind(StringFind)
          EndSelect
  
      EndSelect
                
    Case #PB_Event_Gadget
      Select GEvent  
        Case #StringFindCheck
          If GetGadgetState(#StringFindCheck)=#PB_Checkbox_Checked
            DisableGadget(#StringReplace, #False)
            DisableGadget(#Btn_StringFindReplace, #False)
          Else
            DisableGadget(#StringReplace, #True)
            DisableGadget(#Btn_StringFindReplace, #True)
          EndIf
          
        Case #StringFind 
          StringFind=GetGadgetText(#StringFind)
          
        Case #StringReplace
          StringReplace=GetGadgetText(#StringReplace)
          
        Case #Btn_StringFindEnd
          CloseWindow(#StringFindForm)
          
        Case #Btn_StringFindNext
          ScintillaStringFind(GetGadgetText(#StringFind))
          
        Case #Btn_StringFindReplace
          ScintillaStringReplace(StringFind, StringReplace)
          
      EndSelect
        
    Case #PB_Event_CloseWindow
      End
  EndSelect
ForEver
Last edited by falsam on Mon Sep 24, 2012 9:19 am, edited 3 times in total.

➽ Windows 11 64-bit - PB 6.21 x64 - AMD Ryzen 7 - NVIDIA GeForce GTX 1650 Ti

Sorry for my bad english and the Dunning–Kruger effect 🤪
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Scintilla find/replace

Post by jassing »

I get an IMA error...

Code: Select all

;Scintilla Callback
Procedure ScintillaCallBack()
	
EndProcedure ; << [ERROR] Invalid memory access. (write error at address 0)
Probably something conflicting -- but it's frustrating... Thanks for the demo -- I keep meaning to implement scintilla in a project, but never seem to get around to it...
User avatar
Crusiatus Black
Enthusiast
Enthusiast
Posts: 389
Joined: Mon May 12, 2008 1:25 pm
Location: The Netherlands
Contact:

Re: Scintilla find/replace

Post by Crusiatus Black »

Works perfectly for me, it's a nice start that shows me how I can do this.
Thank you very much for the example!

Jassing, the code as provided causes the exception? At the EndProcedure keyword?
Have you tried restarting the compiler and re-executing the code?
Image
Bas Groothedde,
Imagine Programming

I live in a philosophical paradoxal randome filled with enigma's!
User avatar
Demivec
Addict
Addict
Posts: 4281
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Scintilla find/replace

Post by Demivec »

jassing wrote:I get an IMA error...

Code: Select all

;Scintilla Callback
Procedure ScintillaCallBack()
	
EndProcedure ; << [ERROR] Invalid memory access. (write error at address 0)
I get the same error.
User avatar
Crusiatus Black
Enthusiast
Enthusiast
Posts: 389
Joined: Mon May 12, 2008 1:25 pm
Location: The Netherlands
Contact:

Re: Scintilla find/replace

Post by Crusiatus Black »

PureBasic version, OS version and x86/x64? :) I would like to reproduce that error.
Image
Bas Groothedde,
Imagine Programming

I live in a philosophical paradoxal randome filled with enigma's!
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Scintilla find/replace

Post by Danilo »

Help says the callback has 2 params:

Code: Select all

  ProcedureDLL ScintillaCallBack(Gadget, *scinotify.SCNotification)
    ;
    ; The ProcedureDLL declaration is important for the callback to work correctly on MacOSX,
    ; on all other OS it has no effect.
    ;
  EndProcedure
User avatar
Demivec
Addict
Addict
Posts: 4281
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Scintilla find/replace

Post by Demivec »

Crusiatus Black wrote:PureBasic version, OS version and x86/x64? :) I would like to reproduce that error.
Win XP x86
User avatar
Demivec
Addict
Addict
Posts: 4281
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Scintilla find/replace

Post by Demivec »

@falsam: I got your example working after making the parameter change suggested by Danillo. It is a great example.

The replace function has one quirk though. It works fine unless there is no text selected before the first replacement is attempted.

To reproduce it:
  • type three lines
    * Click somewhere in the first line without creating a selection
    * Call up the find dialog (it can also be called up before this)
    * Enter a 'find' word for something in the second or third line of the document
    * Enter a 'replace by' word
    * Click 'Find (Replace)'.
The result is nothing will take place without first clicking 'Find Next'.
User avatar
falsam
Enthusiast
Enthusiast
Posts: 632
Joined: Wed Sep 21, 2011 9:11 am
Location: France
Contact:

Re: Scintilla find/replace

Post by falsam »

Sorry for this huge mistake in the callback. I've updated the code.

➽ Windows 11 64-bit - PB 6.21 x64 - AMD Ryzen 7 - NVIDIA GeForce GTX 1650 Ti

Sorry for my bad english and the Dunning–Kruger effect 🤪
User avatar
falsam
Enthusiast
Enthusiast
Posts: 632
Joined: Wed Sep 21, 2011 9:11 am
Location: France
Contact:

Re: Scintilla find/replace

Post by falsam »

Update the code :
I added a bonus: Calculation of the indentation for the next line.

➽ Windows 11 64-bit - PB 6.21 x64 - AMD Ryzen 7 - NVIDIA GeForce GTX 1650 Ti

Sorry for my bad english and the Dunning–Kruger effect 🤪
User avatar
Crusiatus Black
Enthusiast
Enthusiast
Posts: 389
Joined: Mon May 12, 2008 1:25 pm
Location: The Netherlands
Contact:

Re: Scintilla find/replace

Post by Crusiatus Black »

Thanks! :)
Image
Bas Groothedde,
Imagine Programming

I live in a philosophical paradoxal randome filled with enigma's!
User avatar
dobro
Enthusiast
Enthusiast
Posts: 766
Joined: Sun Oct 31, 2004 10:54 am
Location: France
Contact:

Re: Scintilla find/replace

Post by dobro »

Code: Select all

Procedure ScintillaStringFind(StringFind.s)
  Protected Current.l, start.l, Anchor.l
    If StringFind <> ""
      Current = ScintillaSendMessage(#Editor, #SCI_GETCURRENTPOS)
      ScintillaSendMessage(#Editor, #SCI_SETANCHOR, Current)
      ScintillaSendMessage(#Editor, #SCI_SEARCHANCHOR)
      Start = ScintillaSendMessage(#Editor, #SCI_SEARCHNEXT, 0, @StringFind)
      If  Start<> -1
        anchor = ScintillaSendMessage(#Editor, #SCI_GETANCHOR)
        ScintillaSendMessage(#Editor, #SCI_SETSEL, start, anchor)
      Else
        MessageRequester("Find string", "No more matching")
      EndIf
    EndIf
   
EndProcedure
does not work, if the search term contains an emphasis

example: the word "repeated" in french "répété" :cry:


ps : excellent Falsam
dommage ça ne marche plus avec les Accents ... :)
Last edited by dobro on Fri Aug 23, 2013 12:55 am, edited 1 time in total.
Image
Windows 98/7/10 - PB 5.42
■ sites : http://michel.dobro.free.fr/
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Scintilla find/replace

Post by Tenaja »

dobro wrote:does not work, if the search term contains an emphasis

example: the word "repeated" in french "répété" :cry:
That is due to the lack of a UTF8 conversion...see SRod's GoScintilla for a sample.
Post Reply