How to speed up upgrade to extension with search and replace capabilities in VS Code

In this article, I will explain how to use solution search efficiently, and how to replace various concepts throughout the solution using regular expressions on Dynamics 365 Business Central. 

 

1. Global solution search

 

As you probably know, more and more RTC users are upgrading solutions to extensions on-prem or SaaS versions. This means, we cannot open or edit any object by using the RTC development environment as it was before, but we can use the universal development environment – Visual Studio Code. The new development environment on BC does not contain the same “handy” interface with all kinds of objects in one place, but it offers some other powerful features, such as solution file search, VS Code extensions, repository integration etc. 

First of all, how does the solution search work in Visual Studio Code? If we want to search something in the text file, we use a shortcut CTRL+F (Edit->Find), for search and replace – CTRL+H (Edit->Replace). Visual Studio Code search allows you to apply classic search and replaces functionality throughout the files of the desired folder or whole solution. To open solution search, we have to click on the search button in the top left corner, as you can see from the image below, or by using a shortcut CTRL+SHIFT+F.

 

 

As you can see, the “Aa” option is currently marked which stands for a classic “Match case” search. So, what can we achieve by using this? For those who thought that now we cannot search an object by its ID anymore – that is not true. If we enter “Codeunit 50000” in the “Search” field, we can find a “Codeunit” with the ID of 50000. Also, we can find objects from -Base Application and find specific cases where the objects are used in. For example, let’s find all Table 18 “Customer” usages as a variable or procedure parameter. The idea is to think about all possible appearances in AL objects. So, I managed to find 3 cases, where a table can be specified as a variable or parameter:

 

  • VariableName: Record 18;
  • VariableName: Record Customer;
  • VariableName: Record “Customer”;

 

As you probably noticed, VariableName can be different in every object, for example: Customer, Cust, TempCust, Cst etc. But one of the parts: “: Record 18;”, “: Record Customer;”, “Record “Customer” must exist in the object containing “Customer” variable declaration. So, we can enter any of the parts separately in the “Search” window and find all the part occurrences. 

 

So, by using the “Match case” global search we can find keywords that have only one condition. Also, it takes a lot of time to search cases 1 by 1. Is it possible to combine more than one search

A regular expression (or just regex) is a sequence of characters that define a search pattern. I will not explain regex itself, but I will teach how to use it to group different search parts into one. First of all, we have to select in the global search block, that we are going to use a regular expression instead of “Match case”. This can be done by marking the following button:


 

As you can see, the previous case with the “Customer” table as a variable is already solved in the search window. Search parts in the regex can be separated by using brackets “( )”. To combine those groups, we can use the symbol ‘|’ which stands for “OR”. So, if we use the pattern (1)|(2)|(3) – the regex will find any digit and check if it is 1 or 2 or 3. If it is, the digit is highlighted in orange. So, let’s combine the previous example with “Customer” table occurrences. The first step is to identify search groups and put them into brackets:

 

  • (: Record 18;)
  • (: Record Customer;)
  • (: Record “Customer”;)

 

After that, put all 3 groups into one sequence separated by the ‘|’ symbol:
(: Record 18;)|(: Record Customer;)|(: Record “Customer”;)

Lastly, copy this completed regular expression line in the search window. This sequence will find and highlight all Table 18 “Customer” usages as a variable or parameter in the whole solution. By using these steps, you can easily group every search part in one sequence without using complex regular expressions, you only have to identify all possible search groups.

 

2. Global replace using regular expressions

 

Global search on BC can be used not only to find something but also to fix or replace AL code. For example, all reports have their respective RDLC layout files. Reports in AL have separate functional *.al files and property RDLCLayout, which stands for the RDLC layout file path (e.g. ‘./SRC/Custom/Reports/CustomerReport.rdlc’). What if we move the layout file to another destination?

RDLCLayout property will not change to another location automatically, so we will have to change it manually. Imagine if we move all report layouts to a different folder to separate layout files from the functional ones, then we will need to change the layout paths of all reports manually. There is a faster solution for this: global replace and regex. Firstly, we have to identify the part which repeats in every object and highlight it:

CustomerReport.rdlc ‘;

The idea is to read everything till the last slash and replace it with the path we moved RDLC Layout objects to. To read all symbols till the last slash, we have to use regular expression basics:

(RDLCLayout =)(.)*/

„(RDLCLayout =)“ – will find all reports containing RDLCLayout property specified. „(.)*“ – stands for any character repeated 0 or more times (This will catch any letter, slash, quote and dot). To return any special symbol, we have to use a „“ before the symbol (e.g. “n“ – newline, “{“ – bracket, “.“ – dot) in regex expressions, so „/“ – will return the last ‚/‘ slash. Let‘s assume we separate RDLC layout files from report .al files and move them to folder „Layouts“:

./SRC/Custom/Reports/Layouts/

Since we already have the path we need to move layouts too, just put this in the replacement window and add „RDLCLayout = ‘“ property at the start:

Click on the „Replace All“ button. That is it, all layout paths have been replaced successfully. All in all, a global replacement can be used in AL to replace something in the whole solution to reduce manual work.

 

3. Add something repetitive in the object or solution

 

Regular expressions can be also used to add or replace AL code in the object. For example, we create a page containing parts, actions, system parts fields etc. and we want to add “ApplicationArea = All;” in all page parts. If we have 4 or 5 fields specified, we can copy and paste and it will not take a fair share of time. Let’s assume that we have 100 fields, 45 actions and 10 parts on our page.

It will take a lot of time to paste “ApplicationArea = All;” in all of them. The solution for this is to create a toolkit using other programming languages or just simply create a regular expression to add “ApplicationArea = All;” in the page object where needed. Firstly, we have to think about all cases where ApplicationArea property can be added.

So, ApplicationArea can be inserted after page parts: action, part, the system part, field. We have to place it after the first bracket, so the idea is to find all the first brackets of those page parts. For this, we will need some regular expression basics, because this will be a more complex pattern. To start creating a regex, we have to define the idea and split it into steps:

 

  • Find the words “action”, “part”, “systempart” and “field”.
  • Find the first ‘(‘ bracket.
  • Go through all symbols till the end of the line.
  • Go to the new line and find all spaces till we get the first ‘{‘ bracket after which we place “ApplicationArea = All;”

 

So basically, we have to read code blocks (using regex) after which we want to insert something. Let’s combine the first step, and it should look like this: “(action|part|systempart|field)”. For the second part, we have to find only one symbol ‘(‘.

To specify one symbol in regex, we have to put a slash before it: “(“. Now we have to read all symbols till the end of the line. For this, we will use some regex basics: “(.)*(s)*(n)*({)”. “(.)*” – will find all visible characters (e.g. dots, semi-colons, numbers letters). “(s)*” – will find all invisible chars (e.g. whitespaces, tabs, line breaks). “(n)*” – stands for the new line (e.g. Enter). “({)” – will find the first bracket after which we will specify the “ApplicationArea” property. Multiplier “*” stands for 0 or more times repeated because there could be a lot of spaces, symbols and letters in the line. Without this multiplier, the regex will try to find only one of each – symbol, space or newline. So, all steps combined, we have this search pattern: “(action|part|systempart|field)((.)*(s)*(n)*({)”.

If you paste it in the object, find a window and mark the regex button, it should highlight all page parts, after which we are going to insert the ApplicationArea property. To place something after every part that the search pattern has found, we have to use “Replace” functionality. In the “Search” box we paste the previously created regex, and in the “Replace” box we have to place the sentence we would like to insert – “ApplicationArea = All;”

To not delete the parts found by the regex pattern, we also need to write “$&” symbols at the beginning of the pattern in “Replace” box and also add a new line symbol to follow the AL code standards – “n”. All in all, the search block should look like this:

When you set up everything, just click on the “Replace All” button and save the file (CTRL+ S). Saving the file will format everything – missing spaces will be automatically added. That’s it, “ApplicationArea = All;” has been added successfully. 

In conclusion, regular expressions can speed up manual work in VS Code and instead of creating tools to automate work in AL programming language, you can simply use global search and regular expressions to achieve efficient code modifications. What is even better, you only need a basic knowledge of regular expressions to start working with the VS Code global search.

 

4. Useful regular expressions

 

Here are some useful regular expressions with replacing statements that I use quite frequently while coding in AL:

  1. Remove ID’s from functions, parameters and variables when copying RTC code block to AL (e.g. PROCEDURE TranslateDescription@1(VAR PaymentTerms@1000 : Record 3):

Search: @(d+)

Replace:

  1. To reduce warnings in the project, remove scope ‘Internal’ from all procedures:

Search:     [Scope(‘Internal’)]

Replace:

  1. “ApplicationArea = All;” addition to page parts:

Search: (action|part|systempart|field)((.)*(s)*(n)*({)

Replace:  $&n ApplicationArea = All;

  1. RDLC layout path switch:

mSearch: (RDLCLayout =)(.)*/

Replace:  RDLCLayout = ‘./SRC/Custom/Reports/Layouts/

  1. Word layout path switch:

Search: (WordLayout =)(.)*/

Replace:  WordLayout = ‘./SRC/Custom/Reports/WordLayouts/

  1. Find all Table “Object” occurrences and references:

Search: (TableRelation = Object;)|(Record Object;)|(Record 2000000001;)|((,)+Object(.)+)|((()+Object(.)+)|((; “)+Object(“))+)|((; )+Object())+)|(TableRelation = Object.)|(Record “Object”) 

We hope you found this article on capabilities in VS Code for Dynamics 365 Business Central useful and it will help you to save time speeding your upgrade to extensions while using VS Code by following the steps given.