1

The single most annoying feature in Excel's built-in VBA editor is—in my opinion—the aggressive autoformatting of the code, which insists on rewriting what I have typed as soon as the cursor leaves the line. It is particularly distressing that the editor collapses all whitespace, thus preventing any meaningful code alignment. For example, if I try to align a sequence of assignments by the equals sign with values aligned by the decimal separator:

price    = 10.01
quantity =  3.2
vat      =  0.11

the editor inevitably scrambles it by collapsing all spaces:

price = 10.01
quantity = 3.2
vat = 0.11

Is there any way to avoid this kind unwelcome autoformatting?

T.M.
  • 9,436
  • 3
  • 33
  • 57
Anton Shepelev
  • 922
  • 9
  • 19
  • 1
    Not much consolation, but at least you can align your type declarations in `Dim ... As ...` :-; @Ant_222 - Or would you like to cut your variables' lengths? – T.M. Mar 01 '21 at 12:02
  • You can also change editor for example visual studio. there is option to do that :) – Tomasz Mar 01 '21 at 12:22
  • @T.M. Sure, I have already found out about declarations, whereas truncating variable names, or padding them with underscores, is risky: colleagues will frown at me. – Anton Shepelev Mar 01 '21 at 13:03
  • @Tomasz, do you mean a provision in *Excel* for an external code editor, or simply suggest that I write my code externally and paste it into *Excel*? If the latter, then it is not going to work because the code will be reformatted upon insertion. And if it did, it would slow down the edit-check-compile cycle. – Anton Shepelev Mar 01 '21 at 13:05
  • microsoft visual studio is platform for developers. You can write code, compile and debug in excel directly by VS. but then you dont have acces to the code by vbe. – Tomasz Mar 01 '21 at 13:16
  • @Tomasz: that cannot be. See, for example, [this](https://stackoverflow.com/q/23173694/2862241) question. Perhaps you misunderstood my question and proposed that I develop a *.NET* program accessing *Excel* via *Interop*? If not, then can you please explain to me how to develop in native *Excel VBA* using *Visual Studio*. You mentioned compilation, but I fear VBA is not a compiled language but a script... – Anton Shepelev Mar 01 '21 at 14:59
  • in visual studio you can do some addins to for example ribbon. its still visual basic language but you dont have acces to code from visual basic editor in excel. its script as u say. you dont need to code in .net environment, you can create console app, librarys etc. example https://www.youtube.com/watch?v=jsEjOjrcJ8k – Tomasz Mar 01 '21 at 15:54
  • @Tomasz, so you made it very clear that you did not understand my question. If I were writing an *Excel* add-in or an external program for the creation of *Excel* files, I certainly should not use VBA—the language about which I ask this question. – Anton Shepelev Mar 01 '21 at 17:09
  • @Ant_222 fyi posted a simple class approach to start with, but sort of overkill :-) – T.M. Mar 01 '21 at 20:51

1 Answers1

1

Assignment cosmetics :-)

There's neither a special VBE property to change the VBE (autoformatting) options directly nor a way to do it programatically. - So afaik VBE irrevocably forces autoformatting upon the user by partial workarounds.

a) Class method

For the sake of the art and just for fun an actually (very) basic class approach to give you a starting idea; assignment arguments are passed as strings allowing any optical formatting - if that's what you really want:

Example call in current module

Sub ExampleCall()
    Dim x As New cVars
    
    x.Add "price    =    11.11"           ' wrong assignment
    '...
    x.Add "price    =    10.01"           ' later correction
    x.Add "quantity =  1241.01"
    x.Add "vat      =     0.11"
    
    Debug.Print "The price is $ " & x.Value("price")
End Sub

Class module cVars

Option Explicit
Private dict As Object

Sub Add(ByVal NewValue As Variant)
    'split string tokens via equal sign
    Dim tmp
    tmp = Split(Replace(Replace(NewValue, vbTab, ""), " ", "") & "=", "=")
    'Identify key and value item
    Dim myKey As String, myVal
    myKey = tmp(0)
    myVal = tmp(1): If IsNumeric(myVal) Then myVal = Val(myVal)
    'Add to dictionary
    If dict.exists(myKey) Then
        dict(myKey) = myVal
    Else
        dict.Add myKey, myVal
    End If
    'Debug.Print "dict(" & myKey & ") =" & dict(myKey)
End Sub

Public Property Get Value(ByVal myVarName As String) As Variant
    'get variable value
    Value = dict(myVarName)
End Property

Private Sub Class_Initialize()
    'set (late bound) dict to memory
    If dict Is Nothing Then Set dict = CreateObject("Scripting.Dictionary")
End Sub

Private Sub Class_Terminate()
    Set dict = Nothing
End Sub


Edit #1 as of 3/3 2021

b) Rem Evaluation method

Once again only for the sake of the art a way to read assignments entered into outcommented code lines via, yes via Rem (heaving a deep sigh for this archaic use originating from former Basic times) as it allows to format data with any wanted spaces or tabs and won't be mixed up hopefully with current outcommentings via apostrophe '.

This Test procedure only needs the usual declarations plus some assignment calls as well as the mentioned Rem part. Two simple help procedures get code lines, analyze them via a dictionary class cVars and eventually assign them.

Note that the following example

  • needs a library reference to Microsoft Visual Basic Extensibility 5.3 and
  • uses the unchanged class cVars of section a) simply to avoid rewriting it.
Option Explicit
Private Const THISMODULE As String = "Module1"      ' << change to current code module name

Sub Test()                                          ' procedure name of example call
    'Declare vars
    Dim price    As Double: Assign "price", price
    Dim quantity As Double: Assign "quantity", quantity
    Dim vat      As Double: Assign "vat", vat
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'Enter assignments via Rem(ark)
    '(allowing any user defined formatting therein)
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Rem price    =    10.01
    Rem quantity =  1241.01
    Rem vat      =     0.11
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Debug.Print quantity & " à $" & price & " = " & Format(quantity * price, "$#,##0.00")
    
End Sub

Help procedure Assign evaluating Rem codelines in procedure Test

Sub Assign(ByVal myVarName As String, ByRef myvar)
    Const MyProc As String = "Test"
    Dim codelines
    getCodelines codelines, THISMODULE, ProcedureName:=MyProc
    'Debug.Print Join(codelines, vbNewLine)
    
    Dim x As New cVars                          ' set class instance to memory
    Dim line As Variant, curAssignment
    For Each line In codelines
        curAssignment = Split(line, "Rem ")(1)  ' remove Rem prefix from codelines
        If curAssignment Like myVarName & "*" Then
            x.Add curAssignment
            myvar = x.Value(myVarName)
        End If
    Next
    
End Sub

Help procedure getCodelines

Called by above proc Assign. Returns the relevant Rem Codelines from the calling procedure Test. - Of course it would have been possible to filter only one codeline.

Sub getCodelines(ByRef arr, ByVal ModuleName As String, ByVal ProcedureName As String)
    Const SEARCH As String = "Rem "
    'a) set project
    Dim VBProj As Object
    Set VBProj = ThisWorkbook.VBProject
    If VBProj.Protection = vbext_pp_locked Then Exit Sub    ' escape locked projects
    'b) set component
    Dim VBComp As Object
    Set VBComp = VBProj.VBComponents(ModuleName)
    Dim pk As vbext_ProcKind

    'd) get relevant code lines
    With VBComp.CodeModule
        'count procedure header lines
        Dim HeaderCount As Long:  HeaderCount = .ProcBodyLine(ProcedureName, pk) - .ProcStartLine(ProcedureName, pk)
        'get procedure code
        Dim codelines
        codelines = Split(.lines(.ProcBodyLine(ProcedureName, pk), .ProcCountLines(ProcedureName, pk) - HeaderCount), vbNewLine)
        'filter code lines containing "Rem" entries
        codelines = Filter(codelines, SEARCH, True)
    End With
    'return elements
    arr = codelines
End Sub

Don't forget to integrate the class module CVars from section a)!

T.M.
  • 9,436
  • 3
  • 33
  • 57
  • 1
    Ha!—I thought you were using some string-evaluation facility built into *VBA*, but then I saw you implemented it yourself. For obvious reasons, it is not what I need but I appreciate your answer nevertheless. – Anton Shepelev Mar 02 '21 at 09:23
  • Appreciate your feedback @Ant_222 . - Challenging indeed. I have another idea in mind; would need some time, however and maybe not what you'd accept :-) – T.M. Mar 02 '21 at 09:37
  • 1
    Great. If *VBE* irrevocably forces autoformatting upon the user, and it cannot be turned off, then I will mark as correct whosever's answer that says so. – Anton Shepelev Mar 02 '21 at 10:22
  • Quite close to similar approach, but being out of office I need further couple of days; btw upvoted question +:) @Ant_222 – T.M. Mar 02 '21 at 20:31
  • Thanks. Notice that my question as about horizontal alignment in general, the alighment of assignmnets is just as example. – Anton Shepelev Mar 03 '21 at 09:32
  • So I fear my intended edit won't contribute something new @ant_222. - My mentioned idea only tries to evaluate codelines arranged via `Rem` *(sic!)* demonstrating another approach and another optic, but which you might consider needless and unpractical as assignments build only a small aspect. – T.M. Mar 03 '21 at 09:58
  • 1
    Posted the promised Edit and excluded that autoformatting could be turned off programatically :-) @Ant_222 – T.M. Mar 03 '21 at 19:05
  • 1
    Thank you for this interesting example of *VBA* introspection. Can you please fix the alignment in the comment block in your `Sub Test()` [like this](https://pastebin.com/raw/bNe2getP)? I have tried to do it myself, but *SO* would not accept so small a correction. – Anton Shepelev Mar 04 '21 at 09:19
  • 1
    Thank you *T.M.*, and so be it. – Anton Shepelev Mar 05 '21 at 09:20