Seite 1 von 3

PB-Tool: Alle Verweise finden

Verfasst: 17.08.2014 19:51
von Kiffi
Hallo,

im Visual Studio kann man mit der rechten Maustaste auf eine Variable oder eine Prozedur klicken und im dann aufklappenden Menü auf "Alle Verweise finden" klicken, um alle Codezeilen aufgelistet zu bekommen, die den angeklickten Suchbegriff enthalten.

Hier ist so was ähnliches für PureBasic, welches als PB-Tool eingerichtet werden kann (leider unterstützt die PB-IDE das nicht über das Popup-Menü der Maus, aber mit einem Keyboard-Shortcut eingerichtet ist funktioniert es auch ganz komfortabel.)

Bild

Code: Alles auswählen

; FindAllReferences

EnableExplicit

Enumeration ; Windows
	#frmMain
EndEnumeration
Enumeration ; Gadgets
	#frmMain_References
EndEnumeration
Enumeration ; Menu-/Toolbaritems
	#frmMain_Shortcut_Escape_Event
EndEnumeration

Global PbIdeHandle = Val(GetEnvironmentVariable("PB_TOOL_MainWindow"))
If PbIdeHandle = 0 : End : EndIf

Global ScintillaHandle = Val(GetEnvironmentVariable("PB_TOOL_Scintilla"))
If ScintillaHandle = 0 : End : EndIf

Procedure.s RemoveLeadingWhitespaceFromString(InString.s)
	
	While Left(InString, 1) = Chr(32) Or Left(InString, 1) = Chr(9)
		InString = LTrim(InString, Chr(32))
		InString = LTrim(InString, Chr(9))
	Wend
	
	ProcedureReturn InString
	
EndProcedure

Procedure.s GetScintillaText()
	
	Protected ReturnValue.s
	
	Protected length
	Protected buffer
	Protected processId
	Protected hProcess
	Protected result
	
	length = SendMessage_(ScintillaHandle, #SCI_GETLENGTH, 0, 0) 
	If length
		length + 2
		buffer = AllocateMemory(length)
		If buffer	
			SendMessageTimeout_(ScintillaHandle, #SCI_GETCHARACTERPOINTER, 0, 0, #SMTO_ABORTIFHUNG, 2000, @result)
			If result
				GetWindowThreadProcessId_(ScintillaHandle, @processId)
				hProcess = OpenProcess_(#PROCESS_ALL_ACCESS, #False, processId)
				If hProcess
					ReadProcessMemory_(hProcess, result, buffer, length, 0)	
					ReturnValue = PeekS(buffer, -1, #PB_UTF8)
				EndIf
			EndIf
		EndIf
		FreeMemory(buffer)
	EndIf
	
	ProcedureReturn ReturnValue
	
EndProcedure

Procedure frmMain_SizeWindow_Event()
	ResizeGadget(#frmMain_References, #PB_Ignore, #PB_Ignore, WindowWidth(#frmMain) - 20, WindowHeight(#frmMain) - 20)
EndProcedure

Procedure frmMain_References_Event()
	
	Protected SelectedLine
	
	SelectedLine = Val(GetGadgetItemText(#frmMain_References, GetGadgetState(#frmMain_References), 0))
	
	If SelectedLine > 0
		SendMessage_(ScintillaHandle, #SCI_GOTOLINE, SelectedLine - 1, 0)
		SendMessage_(ScintillaHandle, #SCI_ENSUREVISIBLE, SelectedLine - 1, 0)
		SetForegroundWindow_(PbIdeHandle)
		SetActiveWindow_(PbIdeHandle)
	EndIf
	
EndProcedure

Define SelectedWord.s = GetEnvironmentVariable("PB_TOOL_Word")
If SelectedWord = "" : End : EndIf

Define ScintillaText.s = GetScintillaText()
If ScintillaText = "" : End : EndIf

Define Line.s
Define CountLines, LineCounter
Define CountTokens, TokenCounter
Define WWE
Define RegexLines, PbRegexTokens

Structure sFoundReference
	LineNo.i
	Reference.s
EndStructure

NewList FoundReference.sFoundReference()

Dim Tokens.s(0)

;http://www.purebasic.fr/english/viewtopic.php?f=12&t=37823
RegexLines = CreateRegularExpression(#PB_Any , ".*\r\n")
PbRegexTokens = CreateRegularExpression(#PB_Any, #DOUBLEQUOTE$ + "[^" + #DOUBLEQUOTE$ + "]*" + #DOUBLEQUOTE$ + "|[\*]?[a-zA-Z_]+[\w]*[\x24]?|#[a-zA-Z_]+[\w]*[\x24]?|[\[\]\(\)\{\}]|[-+]?[0-9]*\.?[0-9]+|;.*|\.|\+|-|[&@!\\\/\*,\|]|::|:|\|<>|>>|<<|=>{1}|>={1}|<={1}|=<{1}|={1}|<{1}|>{1}|\x24+[0-9a-fA-F]+|\%[0-1]*|%|'")

CountLines = CountString(ScintillaText, #CRLF$)

Dim Lines.s(0)

CountLines = ExtractRegularExpression(RegexLines, ScintillaText, Lines())

SelectedWord = LCase(SelectedWord)

For LineCounter = 0 To CountLines - 1
	
	Line = Lines(LineCounter)	
	
	CountTokens = ExtractRegularExpression(PbRegexTokens, Line, Tokens())
	
	For TokenCounter = 0 To CountTokens - 1	
		If SelectedWord = LCase(Tokens(TokenCounter))
			AddElement(FoundReference())
			FoundReference()\LineNo = LineCounter + 1
			FoundReference()\Reference = Line
		EndIf
	Next
	
Next

If ListSize(FoundReference()) = 0 : End : EndIf

OpenWindow(#frmMain, 
           #PB_Ignore,
           #PB_Ignore, 
           600,
           300,
           "All references for: '" + SelectedWord + "'",
           #PB_Window_SystemMenu | 
           #PB_Window_SizeGadget | 
           #PB_Window_ScreenCentered)

StickyWindow(#frmMain, #True)

ListIconGadget(#frmMain_References, 
               10, 
               10,
               WindowWidth(#frmMain) - 20, 
               WindowHeight(#frmMain) - 20,
               "LineNo.", 
               50,
               #PB_ListIcon_FullRowSelect |	
               #PB_ListIcon_GridLines |
               #PB_ListIcon_AlwaysShowSelection)

AddGadgetColumn(#frmMain_References, 1, "Reference", 400)

ForEach FoundReference()
	AddGadgetItem(#frmMain_References, -1, Str(FoundReference()\LineNo) + #LF$ + FoundReference()\Reference)	
Next

AddKeyboardShortcut(#frmMain, #PB_Shortcut_Escape, #frmMain_Shortcut_Escape_Event)
BindEvent(#PB_Event_SizeWindow, @frmMain_SizeWindow_Event(), #frmMain)
BindGadgetEvent(#frmMain_References, @frmMain_References_Event())
SetActiveGadget(#frmMain_References)

Repeat
	
	WWE = WaitWindowEvent()
	
	If (WWE = #PB_Event_Menu And EventMenu() = #frmMain_Shortcut_Escape_Event) Or (WWE = #PB_Event_CloseWindow)
		Break
	EndIf
	
ForEver
Grüße ... Peter

P.S.: Der Gültigkeitsbereich von Variablen wird noch nicht beachtet. Vielleicht baue ich das später mal ein...

// Edit:

* Zeilenfehler behoben. (c4s)
* Groß- und Kleinschreibung wird jetzt nicht mehr beachtet. (Nino)

Re: PB-Tool: Alle Verweise finden

Verfasst: 17.08.2014 20:02
von RSBasic
Super Idee. :allright:
So ein Tool stand sogar in meiner ToDo-Liste, welches ich gerne umsetzen wollte, aber hat sich nun erledigt.
Danke fürs Schreiben und Bereitstellen. :allright:

Re: PB-Tool: Alle Verweise finden

Verfasst: 18.08.2014 09:20
von Rings
Danke fürs teilen, sehr hilfreich !

Re: PB-Tool: Alle Verweise finden

Verfasst: 18.08.2014 10:06
von c4s
Danke! :allright:

Kleines Problem: Bei mir ist jedes Ergebnis eine Zeile zu "früh", d.h. der Fund ist bspw. in Zeile 11 wird aber als 10 angezeigt (und springt dann auch zu 10). Ist das bei euch nicht der Fall?

Re: PB-Tool: Alle Verweise finden

Verfasst: 18.08.2014 10:17
von Kiffi
@c4s: ups, ja, ein Fehler (habe ich oben korrigiert).

Bitte folgende Zeile:

Code: Alles auswählen

FoundReference()\LineNo = LineCounter
in dieses hier ändern:

Code: Alles auswählen

FoundReference()\LineNo = LineCounter + 1
Danke für den Hinweis & Grüße ... Kiffi

Re: PB-Tool: Alle Verweise finden

Verfasst: 18.08.2014 14:40
von NicTheQuick
Oh, ich merke gerade, dass das ja gar nicht unter Linux geht. :cry:

Re: PB-Tool: Alle Verweise finden

Verfasst: 18.08.2014 14:55
von Tommy
Tolles Tool :allright:
@NickTheQuick: Nicht gleich aufgeben. :D
Man kann es doch konvertieren. Man muss nur die GTK APIs für Process und Scintilla finden und nutzen.
Dann geht es auch unter Linux. :)
Da du Linuxer bist kannst du auch gleich damit anfangen dann können auch die anderen 3 Linuxer nutzen.
Viel Glück :D

Re: PB-Tool: Alle Verweise finden

Verfasst: 18.08.2014 14:59
von Nino
Schönes Tool, vielen Dank! :allright:

Zur Zeit wird beim Vergleich ja Groß- und Kleinschreibung berücksichtigt.
Ich schreibe in der Regel meine Identifizierer auch einheitlich, also z.B. nicht mal "Foo" und mal "foO", einfach weil das schöner aussieht. Da man sich aber auch mal vertippen kann und dem PB-Compiler die Groß- und Kleinschreibung egal ist, wäre evtl. zu überlegen, Zeile 121 zu ändern:

Code: Alles auswählen

If LCase(SelectedWord) = LCase(Tokens(TokenCounter))
( Gut, LCase(SelectedWord) besser nur 1x außerhalb der Schleife. ;-) )
P.S.: Der Gültigkeitsbereich von Variablen wird noch nicht beachtet. Vielleicht baue ich das später mal ein...
Das wäre natürlich nicht schlecht. :-)

Danke nochmal!

Re: PB-Tool: Alle Verweise finden

Verfasst: 19.08.2014 13:12
von dige
Danke Kiffi, das ist sehr nützlich!

Re: PB-Tool: Alle Verweise finden

Verfasst: 19.08.2014 14:02
von NicTheQuick
Tommy hat geschrieben:@NickTheQuick: Nicht gleich aufgeben. :D
Man kann es doch konvertieren. Man muss nur die GTK APIs für Process und Scintilla finden und nutzen.
Dann geht es auch unter Linux. :)
Da du Linuxer bist kannst du auch gleich damit anfangen dann können auch die anderen 3 Linuxer nutzen.
Viel Glück :D
Das hat nichts mit Glück zu tun. Bei manch anderen hier vielleicht schon, aber bei mir zumindest nicht. <)
Momentan bin ich nur etwas faul und hab außerdem wenig Zeit. Und so wichtig ist mir dieses Tool jetzt auch nicht. ;)

Aber ich hätte einen Verbesserungsvorschlag.
Ich würde das Fenster zunächst rahmenlos machen. Sobald man mit dem Mauszeiger darüber fährt, sollte sich eine Möglichkeit einblenden es sticky zu machen, sodass man es irgendwo hin schieben kann und es immer sichtbar bleibt, falls man öfter hin und her springen möchte.

PS.: Wieso schreiben mich hier eigentlich so viele immer falsch? :?