OmniPascal 0.13.0 – Load project, compile and run

Load a project, compile and run

Introducing automatic build script generation

You are now able to load a project file in Visual Studio Code. You can either click the new OmniPascal project indicator in the status bar or execute the new command OmniPascal: Load project. Pick a .dpr, .dpk, .lpr or .lpk file to open it. When it’s done you will see the currently loaded project file in the status bar.

The search path will be adjusted automatically when you open a project file.
If the new setting omnipascal.createBuildScripts is set to true (it’s false by default) then a tasks.json file and a .bat file will be generated as soon as a project is loaded or the currently loaded project file changes. The generated tasks.json defines both a build task and a test task. The build task will simply compile the loaded project while the test task will start the compiled application with the run parameters defined in the .dproj or .lpi file. If there is no .dproj or .lpi file for the project then OmniPascal won’t create a build script. So there are no auto generated build scripts for old Delphi projects.

The generated build scripts rely on MSBuild for Delphi projects and LazBuild for Lazarus projects. OmniPascal needs to know the location of these applications in order to work properly.
The path to MSBuild is defined in the setting omnipascal.msbuildPath. If no path is defined OmniPascal will try to find the path by itself.
The path to LazBuild is be defined in omnipascal.lazbuildPath.

Changes in the OmniPascal settings are not reflected on the fly. You need to restart Visual Studio Code or execute the command Reload Window when you change settings!

IMPORTANT CHANGES
– The settings namespace used for OmniPascal is no longer objectpascal but it’s omnipascal. You need to change the settings in Visual Studio Code. For example: The setting objectpascal.delphiInstallationPath has to be changed to omnipascal.delphiInstallationPath.
– The path to the FreePascal source files is no longer stored in objectpascal.delphiInstallationPath. It’s now stored in omnipascal.freePascalSourcePath.
– FreePascal users need to set omnipascal.defaultDevelopmentEnvironment to FreePascal. The default value is Delphi.

Change log

Features
– Ability to load a project file
– Automatically adjust search path when opening a project file (loaded from .dproj and .lpi files)
– Automatic creation of tasks.json and a build script when loading a project that has a corresponding .dproj or .lpi file
– If DelphiInstallationPath is not defined in the settings then OmniPascal looks for the most recent Delphi installation path itself

Bugfixes
– Fixed visibility of symbols defined in System.pas
– Aliases of full qualified types are now handled properly
– Fixed possible stack overflow when working with a generic class defined in the implementation section
– Fixed random crashes
– Parameterless calls to WriteLn, Write, ReadLn and Read can now be resolved
– Outlining in files with syntax errors works better
– Hints for constants of empty strings are now correct
– Implementations of overloaded methods could not be found when an alias for a parameter type is used in the implementation while the declaration uses the original type name
– Fixed internal error when code completion was requested for objects of a type that could not be resolved
– Fixed broken syntax highlighting for Self, Result and some keywords.

OmniPascal 0.12.0 – Add units to uses clauses

This GIF shows how “Implement interface” automatically adds System.TypInfo to the uses clause and how the new “Add unit to uses” command works.

New features:
– Execute Add unit to uses in order to add a unit to a uses clause without navigating to the top. Open the command palette (by pressing F1 or CTRL+SHIFT+P) and type “Add unit to uses”. Select the uses clause and a list of all available units will appear. Select the one you want and press enter. The command is also bound to ALT+U
– Automatic implementation of interfaces adds missing units to the uses clause
– Member of typed pointers can be resolved

Bugfixes:
– Creation of errors and warnings does no longer stop working after a while
– Constants in classes are now resolved properly
– Indexed access on constant resolves now to the definition of that constant / constant array
– Fixed random crashes

Notable changes:
– General performance improvements. Especially startup and code completion are much faster.

Version 0.11.0 – Implement interfaces

Change log:

  • New warnings for incomplete interface implementations
  • Quickfixes for incomplete interface implementations create method declarations and implementation stubs
  • Fixed compatibility to Visual Studio Code 1.7.0
  • Improved the text that pops up up when hovering a constant
  • Fixed code highlighting in hover popup
  • Bugfix: Hovering a method call now shows the signature of the method’s declaration instead of its implementation
  • Bugfix: “Implement method” produced broken code for methods with open array parameters
  • Bugfix: Method resolution clauses were creating warnings for missing implementations
  • Bugfix: UTF8 files with and without BOM are now handled properly
  • Bugfix: Wrong declaration found when a method parameter has the same as a property
  • Bugfix: Directories having the “hidden” or “system” attribute set were invisible to OmniPascal
  • Bugfix: Message “Ordner nicht angegeben” when opening .pas file from explorer
  • Calls to members of a constructor’s return type can be resolved: Example: TObject.Create.Free
  • Improved performance and stability

OmniPascal 0.10.0 – Intrinsic symbols and castings

Features:
– Members of type casted identifiers can be resolved
– Code completion works even when working with type casts
– Basic data types like Integer or String appear in code completion
– Added support for Delphi Intrinsic Routines for Windows 32 platform
– True, False and Nil now appear in code completion
– Added support for pointer types

Bugfixes:
– Names of nested types in generic classes couldn’t be resolved in method implementations
– Names of nested strict private types can be resolved
– Code completion list doesn’t grow anymore when triggered multiple times in classes which inherit from a specialized generic class
– Fixed occasional crashes of OmniPascalServer.exe when editing code with multiple cursors
– Calls to overloaded methods weren’t always resolved correctly based on the parameter count. (Resolving calls to overloaded methods still doesn’t work when multiple versions of a method accept the same amount of parameters)
– Members of items in generic arrays can be resolved
– Name resolving and code completion for symbols defined in the implementation section now works in initialization and finalization section

…as well as some speed improvements.

OmniPascal 0.9 – Namespaces and more

Features:
– The search path will be indexed on start up
– Code completion in uses sections suggests known unit names
– Support for full qualified names like System.Classes.TStringList
– Code completion only suggests types and namespaces when only a type name makes sense in the current context
– Code completion in interface declarations suggests a GUID
– An error is displayed when a unit name doesn’t match its file name
– An error is displayed for duplicate entries in uses section
– An error is displayed for unresolvable entries in uses sections
– A lightbulb appears on unresolvable uses entries which allows to create that file in the current folder
– Hints of hoverered unit names in uses sections look nicer
– Definitions of redeclared properties can be resolved and are part of code completion
– It’s possible to jump to the initial declaration of a redeclared property
– Support for hidden namespaces in uses section (for example “Classes” can be resolved to “System.Classes”)
– Code completion is disabled when defining a new symbol

Bugfixes:
– Code completion used the wrong scope from time to time especially when hitting the dot inside of if-statements or brackets.
– Signature help now highlights the current parameter as soon as the comma is entered
– Signature help didn’t work when used on a member’s method of an object like ObjectA.Member.Find()
– Warnings for incomplete method definitions in included files were created
– Go to a definition of a symbol which is defined in an included file no longer opens the including file but the include file
– Symbol definitions of included files were part of outlining
– No warnings have been created for missing implementations of overloaded methods if one of those methods already had an implementation
– UTF8 files with BOM header can be parsed now
– Protected symbols which should be invisible were part of code completion in special cases
– References to out parameters without type information (void types) can be found
– Quickinfo for variables of type “file” contained no type information
– Code completion showed empty suggestion item
– Code completion in specialized generic descendants didn’t include protected members of non generic base classes
– Parameterized type names in static method calls couldn’t be resolved
– Method names in static method calls on parameterized type names couldn’t be resolved
…as well as some speed improvements.

OmniPascal 0.8.1 released

New features
– Syntax errors are displayed in the editor
– Method definitions without implementations produce warnings
– Warnings for missing implementations provide a quickfix that creates an empty implementation stub for it. TIP: Open the lightbulb with CTRL+.
– Additional search paths can be defined in configuration file using the "objectpascal.searchPath" parameter. Paths are separated by ;. TIP: "D:\\ThirdPartyComponents\\*" will add the folder "D:\ThirdPartyComponents and all its subfolders recursively to the search path.
– DPR files have now support for code completion
– DPR files have now support for outlining

Bug fixes
– Code completion cleaned up from internal compiler methods
– It was impossible to go to the declaration of a procedure that was not a class member
– Fixed undefined internal file state that occured from time to time
– Parameters were not always displayed correctly when hovering a method

Changes
– Toggle Method declaration/implementation has become more error tolerant
– Outlining huge files is >10 times faster now
– Create code completions in huge files is >20 times faster now
– OmniPascal generally runs faster and consumes less memory
– Some words like as, mod,div etc. are temporarily not displayed as operators (gray in dark default theme) but as keywords (blue). This change has become necassary as Visual Studio Code broke some details in syntax highlighting with the latest release. Probably operators will be displayed in gray again in the future.

How to attach the build process to Visual Studio Code

A lot of people asked for a sample on how to compile a project from within Visual Studio Code and how to get nice formatted compiler messages. VSCode comes with a configurable interface that allows you to define

  • a general command to be executed on each build
  • parameters to that command to build the main project
  • parameters to that command to build and run the test project
  • and a problem matcher that extracts warnings and errors from the compiler output.

This configuration is stored in ${workspaceRoot}/.vscode/tasks.json where ${workspaceRoot} is the path of the folder opened in VSCode.

Technical overview

We create a batch file which accepts two different values as the first parameter – build and test. Depending on its value we execute the corresponding commands. We define a problem matcher in order to convert the compiler’s StdOut into displayable notifications, hints and errors.
After compiling the test command we call the test executable to see its result inside the editor.
Here are two sample configurations. Pick the one that helps you the most.

Configuration for a Delphi project using MSBuild

Compile.bat:

@echo off

SET MSBUILD="C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe"
SET RSVARS="C:\Program Files (x86)\Embarcadero\Studio\16.0\bin\rsvars.bat"

if /i %1%==test (
  SET PROJECT=TestProject\UnitTests.dproj
) else (
  SET PROJECT=MainProject\AwesomeExe.dproj
) 

call %RSVARS%   
%MSBUILD% %PROJECT% "/t:Clean,Make" "/p:config=Debug" "/verbosity:minimal"

if %ERRORLEVEL% NEQ 0 GOTO END

echo. 
if /i %1%==test (
  TestProject\UnitTests.exe
)
:END

tasks.json:

{
    "version": "0.1.0",
    "windows": {
        "command": "${workspaceRoot}/Compile.bat"
    },
    "isShellCommand": true,
    "showOutput": "always",
    "tasks": [
        {
            "taskName": "build",
            "isBuildCommand": true,
            "problemMatcher": {
                "owner": "external",
                "fileLocation": ["relative", "${workspaceRoot}"],                        
                "pattern": {
                    "regexp": "((([A-Za-z]):\\\\(?:[^\\/:*?\\\"<>|\\r\\n]+\\\\)*)?[^\\/\\s\\(:*?\\\"<>|\\r\\n]*)\\((\\d+)\\):\\s.*(fatal|error|warning|hint)\\s(.*):\\s(.*)",
                    "file": 1, 
                    "line": 4,
                    "severity": 5,
                    "code": 6,
                    "message": 7
                }
            }                
        },
        {
            "taskName": "test",
            "isTestCommand": true,
            "problemMatcher": {
                "owner": "external",
                "fileLocation": ["relative", "${workspaceRoot}"],                        
                "pattern": {
                    "regexp": "((([A-Za-z]):\\\\(?:[^\\/:*?\\\"<>|\\r\\n]+\\\\)*)?[^\\/\\s\\(:*?\\\"<>|\\r\\n]*)\\((\\d+)\\):\\s.*(fatal|error|warning|hint)\\s(.*):\\s(.*)",
                    "file": 1, 
                    "line": 4,
                    "severity": 5,
                    "code": 6,
                    "message": 7
                }
            }               
        }                         
    ]
}   

Known issues

  • The Delphi compiler provides file name and line number but it doesn’t provide the column number where a message belongs to. VSCode has to guess the correct column. This can cause the error marks to appear in the wrong columns within the correct lines.

  • File names are reported with paths relative to the .dproj file when the file is part of the project. When a file is not part of the project but inside the search path the Delphi compiler uses the absolute path for that file. VSCode’s problem matcher currently can’t handle both types of file names at the same time. You need to decide via the fileLocation key which kind of file names you want to support. You can’t open messages with relative file names when you set "fileLocation": ["absolute"] and vice versa.

Configuration for a Lazarus project using lazbuild

Compile.bat:

@echo off

SET LAZBUILD=C:\development\lazarus\lazbuild.exe

if /i %1%==test (
  SET PROJECT=TestProject\UnitTests.lpi
) else (
  SET PROJECT=MainProject\AwesomeExe.lpi
) 

%LAZBUILD% %PROJECT% --verbose 

if %ERRORLEVEL% NEQ 0 GOTO END

echo. 
if /i %1%==test (
  TestProject\UnitTests.exe --format=plain -a
)
:END

tasks.json:

{
    "version": "0.1.0",
    "windows": {
        "command": "${workspaceRoot}/Compile.bat"
    },
    "isShellCommand": true,
    "showOutput": "always",
    "tasks": [
        {
            "taskName": "build",
            "isBuildCommand": true,
            "severity": "info",
            "problemMatcher": {
                "owner": "external",
                "fileLocation": ["absolute"],                        
                "pattern": {
                    "regexp": "(([A-Za-z]):\\\\(?:[^\\/:*?\"<>|\\r\\n]+\\\\)*[^\\/\\s\\(:*?\"<>|\\r\\n]*)\\((\\d+),(\\d+)\\)\\s.*(Fatal|Error|Warning|Hint|Note):\\s\\((\\d+)\\)\\s(.*)$",
                    "file": 1, 
                    "line": 3,
                    "column": 4,
                    "severity": 5,
                    "code": 6,
                    "message": 7
                }
            }                
        },
        {
            "taskName": "test",
            "isTestCommand": true,
            "severity": "info",
            "problemMatcher": {
                "owner": "external",
                "fileLocation": ["absolute"],                        
                "pattern": {
                    "regexp": "(([A-Za-z]):\\\\(?:[^\\/:*?\"<>|\\r\\n]+\\\\)*[^\\/\\s\\(:*?\"<>|\\r\\n]*)\\((\\d+),(\\d+)\\)\\s.*(Fatal|Error|Warning|Hint|Note):\\s\\((\\d+)\\)\\s(.*)$",
                    "file": 1, 
                    "line": 3,
                    "column": 4,
                    "severity": 5,
                    "code": 6,
                    "message": 7
                }
            }               
        }                         
    ]
}   

When it’s done

When everything works fine then you can

  • run the build command by pressing CTRL+SHIFT+B
  • run the test command by pressing CTRL+SHIFT+T
  • jump to the next compiler message in the current file with F8
  • jump to the previous compiler message in the current file with SHIFT+F8

Compiler messages

Learn more

Announcing OmniPascal – Open Preview

OmniPascal is the newest way to edit Delphi and Free Pascal code.  It’s going to support all language features Delphi knows. It will give you code completion, quick code navigation, great syntax highlighting and much more.

Today OmniPascal becomes available for open preview! The current version supports already a lot of useful features as you can see on www.omnipascal.com. And there is much more about to come in the future. OmniPascal aims to become the greatest code editing experience Delphi developers have ever seen.

You will find the latest news about the project always here on blog.omnipascal.com.

Share your thoughts about OmniPascal. Help us creating the best tool Delphi and Free Pascal developers deserve!