List of IDE Tools

Working on new editor enhancements?
User avatar
Radical Raccoon
User
User
Posts: 11
Joined: Sat Feb 17, 2018 11:17 pm

Re: List of IDE Tools

Post by Radical Raccoon »

skywalk wrote:Does anyone have a tool that deletes trailing spaces and empty lines from IDE source code?
Checking before recreating existing code...
I may be a little bit late, but I wrote a really simple one a short while ago.
I couldn't come up with a more creative name that I liked so I went with the obvious.

Moreover, this is the first tool I've written for PureBasic so feel free to improve this yourself or make me aware of any improvements that could be made. Thank you. :wink:
Name: Trailing Whitespace Cleaner
Known Supported OS: Windows, Linux, Mac
PB Version: 5.62
Description: Cleans up any trailing whitespace in the current source document.
Setup: Refer to source code, please.

Code: Select all

;---------------------
; Tool Configuration | Author : Radical Raccoon // Version : 5.62
;-----------------------------------------------------------------------------------
; Arguments : "%TEMPFILE"                                                          |
; Options   : Wait until tool quits, Run hidden, Reload Source after tool has quit |
;-----------------------------------------------------------------------------------

; Identifiers
Enumeration
  #Whitespace_RegEx
  #Source_File
EndEnumeration

Procedure CreateBackup(File.s)
  If CopyFile(File, File + ".bak")
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure RestoreBackup(File.s)
  If DeleteFile(File)
    If CopyFile(File + ".bak", File)
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure RemoveBackup(File.s)
  If FileSize(File + ".bak") <> -1
    If DeleteFile(File + ".bak")
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
  EndIf
  ProcedureReturn #True
EndProcedure

Procedure StripTrailingWhitespace(File.s)
  OriginalContents.s
  NewContents.s

  If OpenFile(#Source_File, File, #PB_File_SharedRead|#PB_File_SharedWrite)
    If IsFile(#Source_File)
      OriginalContents = ReadString(#Source_File, #PB_File_IgnoreEOL)
      If MatchRegularExpression(#Whitespace_RegEx, OriginalContents)
        If CreateBackup(File)
          NewContents = ReplaceRegularExpression(#Whitespace_RegEx, OriginalContents, #Empty$)
          If NewContents <> OriginalContents
            FileSeek(#Source_File, 0)
            TruncateFile(#Source_File)
            If Not WriteString(#Source_File, NewContents)
              If RestoreBackup(File)
                MessageRequester("Restored", "Failed to update contents of file. Restored from backup successfully.")
                If Not RemoveBackup(File)
                  MessageRequester("Notice", "Failed to automatically remove backup file: " + File + ".bak")
                EndIf
              Else
                MessageRequester("Error", "Failed to restore from backup!", #PB_MessageRequester_Ok|#PB_MessageRequester_Error)
              EndIf
            Else
              If Not RemoveBackup(File)
                MessageRequester("Notice", "Failed to automatically remove backup file: " + File + ".bak")
              EndIf
            EndIf
          Else
            MessageRequester("Error", "Attempted to clean up trailing whitespace, but nothing appears to have changed.", #PB_MessageRequester_Ok|#PB_MessageRequester_Error)
            MessageRequester("Details", RegularExpressionError())
            If Not RemoveBackup(File)
              MessageRequester("Notice", "Failed to automatically remove backup file: " + File + ".bak")
            EndIf
          EndIf
        Else
          MessageRequester("Error", "Failed to create backup of the temp file. Aborting to avoid potential loss of data.", #PB_MessageRequester_Ok|#PB_MessageRequester_Error)
        EndIf
      Else
        MessageRequester("Notice", "There doesn't appear to be anything to clean up here.")
      EndIf
    EndIf
    CloseFile(#Source_File)
  EndIf
EndProcedure

Procedure AppMain()
  If CountProgramParameters() <> 2
    If CreateRegularExpression(#Whitespace_RegEx, "[ \t]+(\r\n|\n?$)", #PB_RegularExpression_MultiLine)
      StripTrailingWhitespace(ProgramParameter())
      FreeRegularExpression(#Whitespace_RegEx)
    EndIf
  Else
    MessageRequester("Notice", "Please only pass %FILE within quotes as a parameter to this tool.")
  EndIf
EndProcedure

AppMain()
End
Last edited by Radical Raccoon on Fri Mar 02, 2018 6:21 am, edited 10 times in total.
User avatar
skywalk
Addict
Addict
Posts: 3960
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: List of IDE Tools

Post by skywalk »

Sorry, your code does not work.
Also, do NOT delete the target file without verifying it was changed!
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Radical Raccoon
User
User
Posts: 11
Joined: Sat Feb 17, 2018 11:17 pm

Re: List of IDE Tools

Post by Radical Raccoon »

skywalk wrote:Sorry, your code does not work.
Also, do NOT delete the target file without verifying it was changed!
Updated the code. Not sure what platform you're using, but I went ahead and also updated the regular expression to account for
Unix and Windows/DOS style line endings which I forgot to do previously. I use multiple platforms.

Works fine on my end.
User avatar
skywalk
Addict
Addict
Posts: 3960
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: List of IDE Tools

Post by skywalk »

Ok, your latest code is very different. I will check it out in a bit.
I went ahead and wrote my own since I am terrible with regular expressions.
I'll post it when it is clean.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Radical Raccoon
User
User
Posts: 11
Joined: Sat Feb 17, 2018 11:17 pm

Re: List of IDE Tools

Post by Radical Raccoon »

skywalk wrote:Ok, your latest code is very different. I will check it out in a bit.
I went ahead and wrote my own since I am terrible with regular expressions.
I'll post it when it is clean.
I look forward to seeing how you implement it. :)
User avatar
skywalk
Addict
Addict
Posts: 3960
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: List of IDE Tools

Post by skywalk »

Code: Select all

;-{ ct_sci_trimlines.pb
; ==============================================
; REV:  18.02.18, skywalk
;       Code Tool for PureBasic IDE Scintilla editor.
;       Trim whitespace only lines and trailing whitespace.
; =========================================================================
; COMPILE TO: ct_sci-trimlines.exe
; COMPILER OPTIONS:
;   [ ] Use Compiler:     PureBasic 5.62 (Windows-x64)
;   [ ] Use Icon:
;   [ ] Enable inline ASM syntax coloring
;   [ ] Create threadsafe executable
;   [ ] Enable OnError lines support
;   [x] Enable modern theme support (for Windows XP and above)
;   [ ] Request Administrator mode for Windows Vista and above
;   [ ] Request User mode for Windows Vista and above (no virtualization)
;   Library Subsystem:
;   Executable Format:    Windows  ;|Console|Shared DLL
;   CPU:                  All      ;|Dynamic|w/MMX|w/3DNOW|w/SSE|w/SSE2
;   Linker options file:
;   File Format:          UTF-8
;   Version Info:         auto set fields --> %yy.%mm.%dd
; =========================================================================
; TOOL SETTINGS:
;   Edit Tool Settings for each Case:
;   Ex. Commandline: ct_sci-trimlines.exe
;       Arguments: NONE
;       Working Directory:
;       Name: TRIM_LINES
;       Event to trigger the tool: Menu or Shortcut: [Ctrl+t]
; ToolName                Arguments               Shortcut          Description
; ----------------------  ----------------------  ----------------- -----------------------------------------------------------
; TRIM_LINES              NONE                    [Ctrl+t]          Trim whitespace only lines and trailing whitespace.
;-} ct_sci_trimlines.pb
EnableExplicit
ImportC ""
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    _wcslen_(*String) As "wcslen"
    _wcsstr_(*String1, *String2) As "wcsstr"
  CompilerElse
    _wcslen_(*String) As "_wcslen"
    _wcsstr_(*String1, *String2) As "_wcsstr"
  CompilerEndIf
EndImport
Procedure SplitC(*String.Character, Array a$(1), *Delimiter)
  ;nco2k, http://www.purebasic.fr/english/viewtopic.php?p=516082#p516082
  ;skywalk; modified to catch trailing null's.
  ; Ex. "1,2,3,," Splits with ',' -> [1][2][3][][].
  Protected.i *StringEnd, DelimiterLength, ArrayIndex
  Protected.i Resize = 511
  Protected.i nStrings = ArraySize(a$())
  If *String\c
    DelimiterLength = _wcslen_(*Delimiter) * SizeOf(Character)
    If DelimiterLength
      Repeat
        *StringEnd = _wcsstr_(*String, *Delimiter)
        If *StringEnd
          a$(ArrayIndex) = PeekS(*String, (*StringEnd - *String) / SizeOf(Character))
          ArrayIndex + 1
          If ArrayIndex > nStrings
            nStrings + Resize
            ReDim a$(nStrings)
          EndIf
          *String = *StringEnd + DelimiterLength
        Else
          Break
        EndIf
      ForEver
    EndIf
    ReDim a$(ArrayIndex)
    a$(ArrayIndex) = PeekS(*String)   ; Catch final trailing null's if any.
    ArrayIndex + 1
  EndIf
  ProcedureReturn ArrayIndex
EndProcedure
Procedure.s Join(Array a$(1), Delm$=#Empty$, iStart.i=0, iStop.i=-1)
  ; REV:  110301, skywalk
  ;       Speed up String concatenation. 600x faster than x$ + y$.
  ; REV:  120104, skywalk
  ;       Unicode support requires careful use of Enc above.
  ;       If #PB_Compiler_Unicode=1 then Enc = #PB_Unicode
  ;       ElseIf #PB_Compiler_Unicode=0 then Enc = #PB_Ascii or UTF8 works.
  ;       #PB_Compiler_Unicode=1, forces Ascii strings to terminate early.
  ;       The allocated memory is then too small creating an IMA.
  ; REV:  120410, skywalk
  ;       Fixed bug when joining A$(0) of 2 or less elements.
  ; REV:  140720, skywalk
  ;       Dropped Enc.i variable. Follows #PB_Compiler_Unicode now.
  ;       UTF8 needs work since it cannot work if compiled as Ascii.
  ; REV:  140826, skywalk
  ;       Added iStart+iStop to allow joining subsets of A$().
  ;       And error logic for iStart/iStop conditions.
  Protected.i i, k, nBytes, *p, *s
  Protected.s r$
  If iStart < 0
    iStart = 0
  EndIf
  If iStop < 0
    k = ArraySize(a$())
    iStop = k
  Else
    If iStart >= iStop
      iStop = iStart
      k = iStop - iStart
    Else
      k = iStop - iStart + 1
    EndIf
  EndIf
  ; Determine nBytes required to hold string array contents
  For i = iStart To iStop
    nBytes + StringByteLength(a$(i))
  Next i
  If Delm$
    nBytes + k * StringByteLength(Delm$) ; Add room for delimiters
  EndIf
  nBytes + SizeOf(Character)    ; add #Empty$
  ;If nBytes < 1024
  ;  nBytes = 1024
  ;EndIf
  *s = AllocateMemory(nBytes)
  If *s
    If nBytes <= MemorySize(*s) ; Verify enough memory created
      *p = *s   ; Create tracking pointer for concatenating memory
      If Delm$
        CopyMemoryString(@a$(iStart), @*p)
        If k > 0
          CopyMemoryString(@Delm$)
          k = iStop - 1   ; Avoid recalculating k-1 in For-Next loop
          For i = iStart + 1 To k
            CopyMemoryString(@a$(i))
            CopyMemoryString(@Delm$)
          Next i
          CopyMemoryString(@a$(i))
        EndIf
      Else
        CopyMemoryString(@a$(iStart), @*p)
        If k > 0
          For i = iStart + 1 To iStop
            CopyMemoryString(@a$(i))
          Next i
        EndIf
      EndIf
      r$ = PeekS(*s, -1)  ; Grab the concatenated memory
      FreeMemory(*s)
    EndIf
  EndIf
  ProcedureReturn r$
EndProcedure
Procedure.i ct_hpid_from_hW(hW.i)
  Protected.i pid, hpid
  If GetWindowThreadProcessId_(hW, @pid)
    hpid = OpenProcess_(#PROCESS_ALL_ACCESS, 0, pid)
  EndIf
  ProcedureReturn hpid
EndProcedure
Procedure.s ct_sci_GetSelectedText(hSci.i, hpid.i)
  ; REV:  180218, skywalk modified from Stargate:
  ;       http://www.purebasic.fr/english/viewtopic.php?p=507821#p507821
  ; USE:  Get current selected text in the editor.
  Protected.i Length, Format
  Protected.i *mSci, *mtxt
  Protected.s txt$
  If hSci And hpid
    Select SendMessage_(hSci, #SCI_GETCODEPAGE, 0, 0)
    Case 0
      Format = #PB_Ascii
    Case 65001
      Format = #PB_UTF8
    EndSelect
    Length = SendMessage_(hSci, #SCI_GETSELTEXT, 0, 0) + SizeOf(Character)
    *mtxt = AllocateMemory(Length)
    If *mtxt
      *mSci = VirtualAllocEx_(hpid, 0, Length, #MEM_RESERVE | #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
      If *mSci
        SendMessage_(hSci, #SCI_GETSELTEXT, 0, *mSci)
        ReadProcessMemory_(hpid, *mSci, *mtxt, Length - SizeOf(Character), 0)
        VirtualFreeEx_(hpid, *mSci, Length, #MEM_RELEASE)
      EndIf
      txt$ = PeekS(*mtxt, -1, Format)
      FreeMemory(*mtxt)
    EndIf
  EndIf
  ;MessageRequester("GetSelectionText()", txt$)
  ProcedureReturn txt$
EndProcedure
Procedure ct_sci_SetSelectedText(hSci.i, hpid.i, txt$)
  ; REV:  180218, skywalk modified from Stargate:
  ;       http://www.purebasic.fr/english/viewtopic.php?p=507821#p507821
  ; USE:  Replace currently selected editor text(*mSci) with specified text(*mtxt).
  Protected.i Length, Position, Format
  Protected.i *mtxt, *mSci
  If hSci And hpid
    Select SendMessage_(hSci, #SCI_GETCODEPAGE, 0, 0)
    Case 0
      Format = #PB_Ascii
    Case 65001
      Format = #PB_UTF8
    EndSelect
    Length = StringByteLength(txt$, Format)
    *mtxt = AllocateMemory(Length + SizeOf(Character))
    If *mtxt
      PokeS(*mtxt, txt$, #PB_Default, Format)
      ;MessageRequester("SetSelectionText()", txt$)
      *mSci = VirtualAllocEx_(hpid, 0, Length, #MEM_RESERVE | #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
      If *mSci
        WriteProcessMemory_(hpid, *mSci, *mtxt, Length, 0)
        Position = SendMessage_(hSci, #SCI_GETSELECTIONSTART, 0, 0)
        SendMessage_(hSci, #SCI_REPLACESEL, 0, *mSci)
        SendMessage_(hSci, #SCI_SETSELECTIONSTART, Position, 0)
        SendMessage_(hSci, #SCI_SETSELECTIONEND, Position + Length, 0)
        VirtualFreeEx_(hpid, *mSci, Length, #MEM_RELEASE)
      EndIf
      FreeMemory(*mtxt)
    EndIf
  EndIf
EndProcedure
Procedure.s SF_TitleCase(s$)
  ; skywalk; Modified from luis, Little John
  ;   http://www.forums.purebasic.com/english/viewtopic.php?p=370491&sid=c211be8dff9e7412095071dd1feee541#p370491
  ; Capitalize 1st letter of each word found. Ascii and most Unicode but fails with some accented char's.
  ; Proper case capitalizes 1st letter of 1st word.
  ; Words defined with the following delimiters:
  ;   space , ! " # $ % & ' ( ) * + - . /
  ;   tab
  ;   : ; < = > ? @
  ;   [ \ ] ^ _ `
  ;Debug SF_TitleCase("  hmm, w::w w[we are one]   we,  went to neW,"+Chr(9)+"yorK toDay. to buy       sausages  ")
  Protected *p.Character = @s$
  Protected.i newWord = 1
  While *p\c
    If newWord
      *p\c = Asc(UCase(Chr(*p\c)))
      newWord = 0
    Else
      *p\c = Asc(LCase(Chr(*p\c)))
    EndIf
    If *p\c > 31 And *p\c < 48      ; space , ! " # $ % & ' ( ) * + - . /
      newWord = 1
    ElseIf *p\c = #TAB
      newWord = 2
    ElseIf *p\c > 57 And *p\c < 65  ; : ; < = > ? @
      newWord = 3
    ElseIf *p\c > 90 And *p\c < 97  ; [ \ ] ^ _ `
      newWord = 4
    EndIf
    *p + SizeOf(Character)
  Wend
  ProcedureReturn s$
EndProcedure
Procedure.s SF_TrimLines(txt$)
  ; Trim empty or whitespace only lines and RTrim any trailing whitespaces.
  Protected.i i, nLines, nLines2
  Protected.s Delm$ = #CRLF$
  Protected Dim a$(0)
  nLines = SplitC(@txt$, a$(), @Delm$) - 1
  Protected Dim b$(nLines)
  For i = 0 To nLines
    If Len(a$(i))
      If Len(Trim(a$(i)))
        b$(nLines2) = RTrim(a$(i))
        nLines2 + 1
      EndIf
    EndIf
  Next i
  If nLines2
    ReDim b$(nLines2 - 1)
    ; Retain final [CR+LF] in original txt$. Prevents collapsing lines with smaller selections.
    If Right(txt$, 2) = #CRLF$
      b$(nLines2 - 1) + #CRLF$
    EndIf
    txt$ = Join(b$(), #CRLF$)
  Else
    txt$ = " "  ; Write at least 1 empty space. #Empty$ fails.
  EndIf
  ;MessageRequester("SF_TrimLines()", "#SOS" + txt$ + "#EOS")
  ProcedureReturn txt$
EndProcedure
Procedure Main()
  Protected.i hSci = Val(GetEnvironmentVariable("PB_TOOL_Scintilla"))
  Protected.i hpid = ct_hpid_from_hW(hSci)
  ;Protected.i hIDE = Val(GetEnvironmentVariable("PB_TOOL_MainWindow"))
  If hSci And hpid
    Protected.s r$ = ct_sci_GetSelectedText(hSci, hpid)
    If r$
      r$ = SF_TrimLines(r$)
      ct_sci_SetSelectedText(hSci, hpid, r$)
      ;ct_sci_SetSelectedText(SF_TitleCase(r$))
    EndIf
    CloseHandle_(hpid)
  EndIf
EndProcedure
Main()
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Radical Raccoon
User
User
Posts: 11
Joined: Sat Feb 17, 2018 11:17 pm

Re: List of IDE Tools

Post by Radical Raccoon »

This looks really nice. I considered approaching it similarly after noticing some other tools that have utilized Scintilla in this way, but I don't quite know enough about all of that quite yet.
I think I'll just use yours instead at this point. I'll try to learn from it as well, of course. I'd like to develop some better tools in the near future. :P
User avatar
skywalk
Addict
Addict
Posts: 3960
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: List of IDE Tools

Post by skywalk »

Yes, I wind up using many of these type tools to augment the IDE.
I will post more of them when I get a chance.
Also, I find the regular expression library too slow for my needs.
Custom string functions are many orders faster.

Note that I hardcoded #CRLF$ as the newline. You will have to add #LF$ for linux/macos newlines.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
oO0XX0Oo
User
User
Posts: 78
Joined: Thu Aug 10, 2017 7:35 am

Re: List of IDE Tools

Post by oO0XX0Oo »

@skywalk

Is there a way to trim trailing whitespaces, remove lines that consist only of them (whitespaces)
but NOT remove empty lines (those which did not contain any character at all before) in the selected text?

For example:

Code: Select all

  Select IsDayLightSavingTime()
    Case #True
        Debug "Sommerzeit!"
<3 spaces on an empty line>

    Case #False
        Debug "Winterzeit!"<2 trailing spaces>

    Default
        Debug "Unbekannt!"
  EndSelect
Only the
<2 trailing spaces>
and the complete line
<3 spaces on an empty line>
should be removed while the other two already empty lines are retained...
User avatar
skywalk
Addict
Addict
Posts: 3960
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: List of IDE Tools

Post by skywalk »

Yes, just put an Else in SF_TrimLines() and increase b$() and nLines2.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
oreopa
Enthusiast
Enthusiast
Posts: 281
Joined: Sat Jun 24, 2006 3:29 am
Location: Edinburgh, Scotland.

Re: List of IDE Tools

Post by oreopa »

kenmo wrote:...here is a tool I use that adds a couple extra features to the editor.
Great, thanks! Was missing both of those.

EDIT: And my little "contribution"... add as appropriate to kenmos code ... and add new tools with shortcut keys

Code: Select all

    If (LCase(Param) = "upper")
      Send(#SCI_UPPERCASE)
    EndIf
    
    If (LCase(Param) = "lower")
      Send(#SCI_LOWERCASE)
    EndIf

:D
Proud supporter of PB! * Musician * C64/6502 Freak
Post Reply