Seite 1 von 4

PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 08.08.2014 17:53
von Kiffi
Hallo,

mich hat schon immer gestört, dass man nicht auf einen Blick sehen kann, in welcher Procedure man sich befindet.

Aus diesem Grund hier folgender Code, den man zu einem PB-Tool kompilieren kann. Wird dieses Tool aufgerufen (ich habe es mir auf das Tastaturkürzel Shift + Ctrl + P gelegt), so wird die der Name der aktuellen Procedure mittels MessageRequester ausgegeben:

Bild

Bitte beachten: In den Werkzeug-Einstellungen als Argument "%TEMPFILE" eintragen

Code: Alles auswählen

; GetProcedureName

; #################################################################
; In den Werkzeug-Einstellungen als Argumente "%TEMPFILE" eintragen
; #################################################################

EnableExplicit

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()
	
	; thx to sicro (http://www.purebasic.fr/german/viewtopic.php?p=324916#p324916)
	
	Protected ReturnValue.s
	Protected FilePath.s
	Protected File, BOM
	
	FilePath = ProgramParameter(0) ; %TEMPFILE (Datei existiert auch, wenn Code nicht gespeichert ist)
	
	File = ReadFile(#PB_Any, FilePath, #PB_File_SharedRead)
	If IsFile(File)
		BOM = ReadStringFormat(File) ; BOM überspringen, wenn vorhanden
		ReturnValue = ReadString(File, #PB_File_IgnoreEOL | BOM)
		CloseFile(File)
	EndIf
	
	ProcedureReturn ReturnValue
	
EndProcedure

Define ScintillaText.s
Define CursorLine = Val(StringField(GetEnvironmentVariable("PB_TOOL_Cursor"), 1, "x"))
Define Line.s
Define LineCounter

ScintillaText = GetScintillaText()

CompilerSelect #PB_Compiler_OS
	CompilerCase #PB_OS_Windows
		#LineFeed = #CRLF$
	CompilerDefault
		#LineFeed = #LF$
CompilerEndSelect

If ScintillaText <> ""
	
	For LineCounter = CursorLine - 1 To 1 Step - 1
		
		Line = RemoveLeadingWhitespaceFromString(StringField(ScintillaText, LineCounter, #LineFeed))
		
		If Left(LCase(Line), Len("endprocedure")) = "endprocedure"
			Break
		EndIf
		
		If Left(LCase(Line), Len("procedure")) = "procedure" 
			If Left(LCase(Line), Len("procedurereturn")) <> "procedurereturn"
				MessageRequester("You are here:", Line)
				Break
			EndIf
		EndIf
		
	Next
	
EndIf
Grüße ... Kiffi

Edit: Verbesserungsvorschläge von Sicro implementiert. Danke dafür!

Verfasst: 20.08.2014 21:05
von CodeCommander
Dein Tool stürzt mit IMA bei Zeile 42 ab.

Feedback zum Code: Was mir auffiel:
1. Die Variablenbenennung ist nicht einheitlich. Mal schreibst du am Anfang groß und dann doch wieder klein.
2.

Code: Alles auswählen

If PB_TOOL_Scintilla <> ""
Das mit <> "" brauchst du nicht und ist unnötig. Es reicht schon wen du so abfragst:

Code: Alles auswählen

If PB_TOOL_Scintilla
Genauso mit If ScintillaText <> "" --> If ScintillaText
3. Du benutzt sehr viele String Funktionen. Besser und schneller wäre es wenn du reguläre Ausdrücke benutzt weils viel schneller ist als tausende String Funktionen.

Re: PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 20.08.2014 22:27
von c4s
Kiffi hat geschrieben:mich hat schon immer gestört, dass man nicht auf einen Blick sehen kann, in welcher Procedure man sich befindet.
Gute Idee, denn das "Problem" kenne ich auch!

Ich habe auch gleich einen Feature-Request ;) : Das Ergebnis direkt in der Compiler-Statusliste ausgeben. Der offensichtliche Vorteil ist, dass es sich noch integrierter anfühlt. Ich meine mich zu erinnern, dass der Quellcode von "Dead Procedure Remover" (von Danilo, hier) einen Trick/Workaround dafür besitzt. Vielleicht hast du Lust es dir mal anzusehen. Andernfalls werde ich es morgen mal probieren.

Re: PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 20.08.2014 22:33
von NeoChris
Kiffi hat geschrieben:mich hat schon immer gestört, dass man nicht auf einen Blick sehen kann, in welcher Procedure man sich befindet.
Wie muss ich mir das vorstellen? Du musst doch wissen in welcher Procedure du gerade codest? Warum soll man nicht (mehr? Alzheimer?) wissen in welcher Procedure man sich befindet? Oder hast du solche übertriebene langen Proceduren? Wenn ja dann hast du ein sehr schlechtes Code Design. Teile diese doch in mehreren kleineren so das es für dich übersichtlicher ist.

Re: PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 20.08.2014 23:32
von Shardik
CodeCommander hat geschrieben:2.

Code: Alles auswählen

If PB_TOOL_Scintilla <> ""
Das mit <> "" brauchst du nicht und ist unnötig. Es reicht schon wen du so abfragst:

Code: Alles auswählen

If PB_TOOL_Scintilla
Genauso mit If ScintillaText <> "" --> If ScintillaText
Kiffi ist lediglich vorsichtig, weil

Code: Alles auswählen

If PB_TOOL_Scintilla <> ""
die von Fred empfohlene Schreibweise ist. Denn seit PB 5.00 Beta 7 ist schon die frühere Möglichlichkeit, mit

Code: Alles auswählen

If Not Test.s
zu testen, ob der String Test.s leer ist, nicht mehr möglich:
http://www.purebasic.fr/english/viewtop ... 13&t=51880

Daher könnte es durchaus sein, dass irgendwann einmal auch

Code: Alles auswählen

If Test.s
nicht mehr funktionieren könnte. Mit Kiffis Methode ist man daher immer auf der sicheren Seite... :wink:

Verfasst: 20.08.2014 23:38
von CodeCommander
Danke Shardik für deine kompetente Antwort und den Link :)
Sehr interessant und informativ und ich werde absofort auch mit <> "" abrprüfen ob ein String ungleich leer ist.
Dann hat sich meine Frage an Kifi erledigt. :allright:

Re: PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 20.08.2014 23:40
von c4s
NeoChris hat geschrieben:Du musst doch wissen in welcher Procedure du gerade codest? [...] Oder hast du solche übertriebene langen Proceduren? Wenn ja dann hast du ein sehr schlechtes Code Design.
Mit schlechtem Programmierstil hat dies überhaupt nichts zu tun. Eine einzelne Prozedur kann, darf und ist in der Praxis durchaus länger als ca. 40 Zeilen (d.h. der sichtbare Bereich).

Zumindest für mich wäre folgendes ein häufiger Anwendungsfall: Wenn du ein oder sogar mehrere Quelltexte gleichzeitig nach Schlüsselwörtern durchsucht kann es vorkommen, dass der Kontext des Fundes nicht sofort ersichtlich ist. Anstatt nun mühselig hoch scrollen zu müssen bis der Prozedurname sichtbar wird (und dann wieder zurück zur Fundstelle), kann dieses Tool einem sofort weiterhelfen.

Re: PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 20.08.2014 23:50
von NeoChris
Ahhhh danke jetzt weiß ich Bescheid. Daran habe ich noch gar nicht gedacht. Dann ergibt es natürlich Sinn. Danke :allright:

Re: PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 21.08.2014 13:32
von c4s
@NeoChris
Ein weiterer Anwendungsfall ergibt sich mit dem neuen Issue-Feature: Bei Doppelklick auf einen Eintrag springt man sofort zur jeweiligen Zeile im Code - auch hier kann der Prozedurname nicht sofort ersichtlich sein.

c4s hat geschrieben:[...] Ergebnis direkt in der Compiler-Statusliste ausgeben. [...] Vielleicht hast du Lust es dir mal anzusehen. Andernfalls werde ich es morgen mal probieren.
Ein kurzer Test hat gezeigt, dass Danilos Trick mit PB 5.30 ohne (mir unbekannte) Anpassungen leider nicht mehr funktioniert. Es wird wohl an der neuen Unicode-IDE bzw. den damit zusammenhängenden internen Änderungen liegen, denn mit PB 5.22 funktioniert es. Hier ist der Code, der "test" als Statusmeldung ausgeben sollte:

Code: Alles auswählen

EnableExplicit

Global regExPBIDEwin = CreateRegularExpression(#PB_Any, "^PureBasic ([0-9])+(\056)+([0-9])+ (LTS )*\((x86|x64)+\)", #PB_RegularExpression_NoCase)

Global gMainWindow.i = Val( GetEnvironmentVariable("PB_TOOL_MainWindow") )
Global gListBox.i = 0

Procedure EnumWindowsProc(hwnd, lParam)
	Protected.s windowname, classname
	
	If hwnd
		windowname = Space(1024*10)
		GetWindowText_(hwnd, @windowname, 1024*10)
		windowname = PeekS(@windowname, -1)
		
		If windowname <> ""
			If MatchRegularExpression(regExPBIDEwin, windowname)
				classname = Space(1024)
				GetClassName_(hwnd, @classname, 1024)
				
				If Left(classname, 11) = "WindowClass"
					gMainWindow = hwnd
					ProcedureReturn #False
				EndIf
			EndIf
		EndIf
	EndIf
	
	ProcedureReturn #True
EndProcedure

Procedure EnumChildProc(hwnd, lParam)
	Protected.s windowname, classname, classname2
	
	classname = Space(1024)
	GetClassName_(hwnd, @classname, 1024)
	
	If FindString(classname, "ListBox") <> 0
		windowname = Space(1024)
		SendMessage_(hwnd, #WM_GETTEXT, 1024, @windowname)
		windowname = PeekS(@windowname, -1, #PB_UTF8)
		
		classname2 = Space(1024)
		GetClassName_(GetParent_(hwnd), @classname2, 1024)
		
		If FindString(classname2, "Window")
			gListBox = hwnd
			ProcedureReturn #False
		EndIf
	EndIf
	
	ProcedureReturn #True
EndProcedure

Procedure AddStatusMessage(msg.s)
	If gListBox
		SendMessage_(gListBox, #LB_ADDSTRING, 0, @msg)
		SendMessage_(gListBox, #LB_SETTOPINDEX, SendMessage_(gListBox, #LB_GETCOUNT, 0, 0) -1, 0)
	EndIf
EndProcedure

If gMainWindow = 0
	EnumWindows_(@EnumWindowsProc(), 0)
EndIf
If gMainWindow
	EnumChildWindows_(gMainWindow, @EnumChildProc(), 0)
EndIf

AddStatusMessage("test")

Re: PB-Tool: Namen der aktuellen Procedure ausgeben lassen

Verfasst: 21.08.2014 13:42
von Sicro
So funktioniert es unter Windows, Linux und sicherlich auch unter MacOS:

Code: Alles auswählen

; GetProcedureName

; #################################################################
; In den Werkzeug-Einstellungen als Argumente "%TEMPFILE" eintragen
; #################################################################

EnableExplicit

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 FilePath.s
   Protected File
   
   FilePath = ProgramParameter(0) ; %TEMPFILE (Datei existiert auch, wenn Code nicht gespeichert ist)
      
   File = ReadFile(#PB_Any, FilePath, #PB_File_SharedRead)
   If IsFile(File)
      ReadStringFormat(File) ; BOM überspringen, wenn vorhanden
      ReturnValue = ReadString(File, #PB_File_IgnoreEOL | #PB_UTF8)
      CloseFile(File)
   EndIf
   
   ProcedureReturn ReturnValue
   
EndProcedure

Define ScintillaText.s
Define CursorLine = Val(StringField(GetEnvironmentVariable("PB_TOOL_Cursor"), 1, "x"))
Define Line.s
Define LineCounter

ScintillaText = GetScintillaText()

If ScintillaText <> ""
   
   For LineCounter = CursorLine - 1 To 1 Step - 1
      
      CompilerSelect #PB_Compiler_OS
         CompilerCase #PB_OS_Windows
            #LineFeed = #CRLF$
         CompilerDefault
            #LineFeed = #LF$
      CompilerEndSelect
      
      Line = RemoveLeadingWhitespaceFromString(StringField(ScintillaText, LineCounter, #LineFeed))
      
      If Left(LCase(Line), Len("endprocedure")) = "endprocedure"
         Break   
      EndIf
      
      If Left(LCase(Line), Len("procedure")) = "procedure"
         If Left(LCase(Line), Len("procedurereturn")) <> "procedurereturn"
            MessageRequester("You are here:", Line)
            Break   
         EndIf
      EndIf
      
   Next
   
EndIf