├── .github └── workflows │ └── main.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── README_CN.md ├── bin ├── aarch64-linux │ ├── jcf │ └── pasls ├── jcfsettings.cfg ├── win32 │ ├── jcf.exe │ └── pasls.exe ├── x86_64-darwin │ ├── jcf │ └── pasls └── x86_64-linux │ ├── jcf │ └── pasls ├── images ├── doc │ ├── code-snippets.gif │ ├── documentsymbol.gif │ ├── format.gif │ ├── fpctoolkit.gif │ └── quickfix.gif ├── icon-link.svg ├── logo.png └── pascal-project.png ├── package.json ├── package.nls.json ├── package.nls.zh-CN.json ├── pascal-configuration.json ├── snippets └── pascal.json ├── src ├── commands.ts ├── common │ ├── configuration.ts │ ├── escape.ts │ └── util.ts ├── extension.ts ├── formatter.ts ├── languageServer │ ├── client.ts │ ├── codeaction.ts │ └── options.ts └── providers │ ├── project.ts │ └── task.ts ├── syntaxes └── fpc.tmLanguage └── tsconfig.json /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Publish FpcToolKit 4 | 5 | # Controls when the workflow will run 6 | on: 7 | release: 8 | types: 9 | - published 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | release: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: actions/setup-node@v1 21 | with: 22 | node-version: 14 23 | registry-url: https://registry.npmjs.org/ 24 | 25 | - name: Install the dependencies 26 | run: npm i 27 | 28 | - name: Install vsce 29 | run: npm i -g vsce 30 | 31 | - name: Install esbuild 32 | run: npm i -g esbuild 33 | 34 | - name: Build with esbuild 35 | run: esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node 36 | 37 | # 38 | # Package and Upload Extension 39 | # 40 | # NOTE: 41 | # The "vscode:prepublish" script in package.json will be executed to compile the extension 42 | # prior to packaging. 43 | # 44 | - name: Package Extension into .vsix file 45 | id: asset 46 | shell: bash 47 | run: > 48 | vsce package; 49 | echo ::set-output name=vsix_path::$(ls *.vsix) 50 | 51 | - name: Upload .vsix file to Github as release asset 52 | uses: actions/upload-release-asset@v1 53 | env: 54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | with: 56 | upload_url: ${{ github.event.release.upload_url }} 57 | asset_path: ${{ steps.asset.outputs.vsix_path }} 58 | asset_name: ${{ steps.asset.outputs.vsix_path }} 59 | asset_content_type: application/zip 60 | 61 | 62 | - name: Publish 63 | run: vsce publish -p ${{ secrets.VSCE_PAT }} 64 | 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | *.vsix 4 | *.lock 5 | package-lock.json 6 | *.mov 7 | .DS_Store 8 | req.txt 9 | media 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js", 18 | ], 19 | "preLaunchTask": "${defaultBuildTask}" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "${defaultBuildTask}" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | 4 | "files.exclude": { 5 | "out": false // set this to true to hide the "out" folder with the compiled JS files 6 | }, 7 | "search.exclude": { 8 | "out": true // set this to false to include "out" folder in search results 9 | }, 10 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 11 | "typescript.tsc.autoDetect": "off" 12 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "group": "build", 10 | "problemMatcher": [], 11 | "label": "npm: watch", 12 | "detail": "tsc -watch -p ./" 13 | }, 14 | { 15 | "type": "npm", 16 | "script": "compile", 17 | "group": "build", 18 | "problemMatcher": [], 19 | "label": "npm: compile", 20 | "detail": "tsc -p ./" 21 | }, 22 | { 23 | "type": "npm", 24 | "script": "esbuild", 25 | "group": { 26 | "kind": "build", 27 | "isDefault": true 28 | }, 29 | "problemMatcher": [], 30 | "label": "npm: esbuild", 31 | "detail": "npm run -S esbuild-base -- --sourcemap" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .gitignore 3 | media 4 | node_modules 5 | src 6 | .github 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [Unreleased] 2 | - Using lazarus project files 3 | 4 | ## [1.1.9] - 2022-12-17 5 | ## add: 6 | - optimize clean up and build 7 | ## fixed: 8 | - can't rename symbol on version 1.1.8 9 | 10 | ## [1.1.8] - 2022-12-16 11 | ## add: 12 | - add error handle for client to avoid crashing 13 | - change maximumCompletions default to 50 14 | 15 | ## [1.1.6] - 2022-12-06 16 | ## add: 17 | - add build events 18 | 19 | ## [1.1.5] - 2022-11-23 20 | ## fixed: 21 | - can't start language server on linux 22 | 23 | ## [1.1.4] - 2022-10-15 24 | ## fixed: 25 | - quick fix not worked 26 | 27 | ## [1.1.3] - 2022-10-14 28 | ### add: 29 | - code format 30 | - quick fix for [5025] Local variable "xxx" not used 31 | - document symbols navigation 32 | - remove ununsed unit 33 | ### fixed: 34 | - Enhance the stability of the program pasls 35 | 36 | ## [1.1.0] 37 | - pascal language server 38 | - code snippets 39 | - auto completion 40 | - gotoDeclaration, gotoDefinition 41 | - references 42 | - documentHighlight 43 | - i18n support 44 | 45 | ## [1.0.4] - 2020-10-14 46 | ### fixed: 47 | - Throw exception when parsing non-fpc type tasks 48 | 49 | ## [1.0.3] - 2020-10-13 50 | ### fixed: 51 | - error with "fs-extra module not found" 52 | 53 | 54 | ## [1.0.2] - 2020-10-12 55 | ### add: 56 | - Clean menu 57 | 58 | 59 | ## [1.0.1] - 2020-09-17 60 | ### fixed: 61 | - Fixes for issues that don't work under Linux 62 | 63 | ## [1.0.0] - 2020-09-17 64 | - Initial release -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FreePascal Toolkit 2 | `FreePascal Toolkit` is a VSCode extension for developing FreePascal applications. 3 | 4 | ![FreePascal Toolkit preview](images/doc/fpctoolkit.gif) 5 | 6 | [中文文档](README_CN.md) 7 | ## Requirements 8 | 9 | - Install [Lazarus](https://www.lazarus-ide.org/) or [FreePascal](https://www.freepascal.org/download.var) on your system. 10 | 11 | - The extendsion will auto search the path of fpc. If it's not be found, please set the system PATH environment variable, or set `fpctoolkit.env.PP` in vscode's user setting. 12 | 13 | - Install [GDB Debugger - Beyond](https://marketplace.visualstudio.com/items?itemName=coolchyni.beyond-debug) to debug your freepascal program . 14 | 15 | 16 | ## Features 17 | - build freepascal program 18 | - Build 19 | - Rebuild 20 | - Clear 21 | - explorer build tasks 22 | - Customize build tasks 23 | - Inherted from other task 24 | - code snippets 25 | - A lot of snippets for code quick edit. 26 | * class 27 | * if-else 28 | * begin-end 29 | * ... 30 | - auto completion 31 | 32 | ![](images/doc/code-snippets.gif) 33 | 34 | - gotoDeclaration, gotoDefinition 35 | - Use `ctrl+up`,`ctrl+down` to jump between declaration and implementation. 36 | - class and function references 37 | 38 | ![](images/doc/documentsymbol.gif) 39 | 40 | - documentHighlight 41 | - High light for source code 42 | - Identify the compilation conditions for the definition. `{$IFDEF} {ELSE} {$ENDIF}` 43 | 44 | - code format with [jcf cli](https://github.com/coolchyni/jcf-cli) 45 | 46 | ![](images/doc/format.gif) 47 | 48 | - Format source code 49 | - Use `jcfsettings.cfg` as config. Will use lazarus's config if it installed. 50 | - quick fix 51 | - Quick fix for `(5025) Local variable "xxx" not used` 52 | 53 | ![](images/doc/quickfix.gif) 54 | 55 | - auto rename symbols 56 | - Rename function,procedure,variable and it's reference. 57 | - code complete 58 | - Use `ctrl+shift+c` auto implement procedure . 59 | - code actions 60 | - remove unused units 61 | ## Pascal Language Server 62 | 63 | from [pascal-language-server](https://github.com/coolchyni/pascal-language-server) 64 | 65 | An [LSP](https://microsoft.github.io/language-server-protocol/) server 66 | implementation for Pascal variants that are supported by [Free 67 | Pascal](https://www.freepascal.org/), including Object Pascal. It uses 68 | [CodeTools](https://wiki.lazarus.freepascal.org/Codetools) from 69 | Lazarus as backend. 70 | 71 | ## Freepascal Task Settings 72 | 73 | You can add freepascal compile tasks by editing `task.json` in your .vscode folder. 74 | 75 | The task's type is `fpc`. It contains the following configuration items. 76 | 77 | ### Task settings 78 | Field | type | Description | 79 | ------ | ----- | :------------- 80 | file | string|main program file. .lpr or .dpr 81 | type | string|always be `fpc` 82 | cwd | string|current path. Use wrokspace root if null. 83 | cleanExt|string|file extensions for clean file in unitOutputDir. use * for clear all file. default:(.o,.ppu) 84 | buildOption|object|build options 85 | inherited|string| inherit from other task 86 | 87 | ### buildEvent 88 | Field | type | Description | 89 | -------| ---- |:--------------- 90 | before_build | string[] | Run commands before build 91 | after_build_success | string[]| Run commands after build success. 92 | after_build_failure | string []| Run commands after build failure. 93 | 94 | 95 | ### buildOptions 96 | Field | type | Description | 97 | -------| ---- |:--------------- 98 | targetOS | string | Target OS (-T). eg. `linux` `win64` 99 | targetCPU |string| Target cpu family (-P). eg. `x86_64` `i386` 100 | customOptions|string []| Any compile options for fpc. 101 | libPath|string[]|Searchpath for libraries.(-Fl) 102 | outputFile| string| Target file name.(-o) 103 | unitOutputDir| string|Unit output directory.(-FU) 104 | optimizationLevel| number|Optimization levels (-O) 105 | searchPath| string[]|Searchpath for units and other system dependent things.(-Fu) 106 | syntaxMode| string|Syntax Mode (-M) 107 | forceRebuild| boolean|Re-compile all used units, even if the unit sources didn’t change since the last compilation.(-B) 108 | msgIgnore|number[]|Is a list of messages numbers which should not be shown.(-vmxxx) 109 | 110 | example: 111 | ~~~json 112 | { 113 | "version": "2.0.0", 114 | "tasks": [ 115 | { 116 | "label": "debug", 117 | "file": "main.lpr", 118 | "type": "fpc", 119 | "buildOption": { 120 | "unitOutputDir": "./out", 121 | "customOptions": [ 122 | "-dDEBUG", 123 | "-gw2" 124 | ] 125 | } 126 | } 127 | ] 128 | } 129 | ~~~ 130 | 131 | # Thanks 132 | ## HighLight 133 | 134 | Syntaxes from https://github.com/maresmar/ST-Pascal 135 | 136 | ## Format 137 | 138 | Clone and modified from https://github.com/git-bee/jcf-cli 139 | 140 | ## Pascal-language-server 141 | 142 | Clone and modified from 143 | https://github.com/genericptr/pascal-language-server 144 | https://github.com/arjanadriaanse/pascal-language-server 145 | 146 | # Release Notes 147 | 148 | [view changelog](CHANGELOG.md) 149 | 150 | 151 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # FreePascal Toolkit 2 | `FreePascal Toolkit` 是一个用于开发FreePascal程序的 VSCode 应用扩展. 3 | 4 | ![FreePascal Toolkit preview](images/doc/fpctoolkit.gif) 5 | 6 | [English Document](README.md) 7 | ## 准备条件 8 | 9 | - 安装 [Lazarus](https://www.lazarus-ide.org/) 或 [FreePascal](https://www.freepascal.org/download.var) . 10 | - 默认会自动搜索FPC路径,如果找不到,请设置FPC的路径为系统搜索路径,或者在插件里设置 `fpctoolkit.env.PP = FPC程序全路径`. 11 | 12 | - 安装并使用 [GDB Debugger - Beyond](https://marketplace.visualstudio.com/items?itemName=coolchyni.beyond-debug) 进行程序调试 13 | 14 | ## 功能列表 15 | - 编译Free Pascal 程序 16 | - 构建项目 17 | - 清理和构建 18 | - 清理 19 | 20 | - 可视化任务管理 21 | - 支持自定义任务 22 | - 支持从其他任务继承 23 | - 快速代码模版 24 | - 包含非常多的代码模版,用于快速输入代码. 25 | * class 26 | * if-else 27 | * begin-end 28 | * ... 29 | - 智能代码补全,支持函数,过程,类,变量,关键字... 30 | 31 | ![](images/doc/code-snippets.gif) 32 | 33 | - 代码快速导航 34 | - 使用 `ctrl+up`,`ctrl+down` 在函数声明和函数体之间快速跳转. 35 | - 快速访问类和函数定义 36 | 37 | ![](images/doc/documentsymbol.gif) 38 | 39 | - 语法高亮显示 40 | - 源代码高亮 41 | - 能根据编译条件,将`{$IFDEF} {ELSE} {$ENDIF}`之间的无效代码半透明. 42 | - 代码格式化 43 | 44 | - 使用[jcf cli](https://github.com/coolchyni/jcf-cli)格式化源代码 45 | - 使用 `jcfsettings.cfg` 作为配置文件。如果你已经安装了lazarus,本插件将自动使用其配置文件. 46 | 47 | ![](images/doc/format.gif) 48 | 49 | - 快速修复 50 | - 快速修复警告: `(5025) Local variable "xxx" not used` 51 | 52 | ![](images/doc/quickfix.gif) 53 | 54 | - 重命名函数,类,或变量名 55 | - 重命名将会自动更新其相关引用. 56 | - 代码自动完成 57 | - 使用 `ctrl+shift+c` 自动实现函数体 . 58 | - 源代码操作 59 | - 支持删除无用的单元声明 60 | 61 | ## Pascal Language Server 62 | 63 | [pascal-language-server](https://github.com/coolchyni/pascal-language-server)是一个[Free Pascal](https://www.freepascal.org/)实现的[LSP](https://microsoft.github.io/language-server-protocol/) 服务端程序。使用[Lazarus](https://www.lazarus-ide.org/)的[CodeTools](https://wiki.lazarus.freepascal.org/Codetools)作为后台。 64 | 65 | ## 任务设置 66 | 67 | 你可以在.vscode目录下编辑 `task.json` 文件来修改任务选项目。 68 | 69 | 任务类型为 `fpc`. 包含以下可用的配置项: 70 | 71 | ### Task 选项 72 | 字段 | 类型 | 描述 | 73 | ------ | ----- | :------------- 74 | file | string|Free Pascal 项目文件. (.lpr,.dpr) 75 | type | string|必须是 `fpc` 76 | cwd | string|当前工作目录. 如果不设置默认使用vscode工作目录. 77 | cleanExt|string|指定执行清理项目时需要清除的文件名后缀. 输入* 表示清除所有文件. 默认(.o,.ppu,.lfm,.a,.or,.res) 78 | buildOption|object|build 选项 79 | inherited|string| 被继承的任务名 80 | 81 | ### buildEvent 82 | 字段 | 类型 | 描述 | 83 | -------| ---- |:--------------- 84 | before_build | string[] | 编译前执行的命令 85 | after_build_success | string[]| 编译成功后执行的命令 86 | after_build_failure | string []|编译失败后执行的命令 87 | 88 | ### buildOptions 89 | 字段 | 类型 | 描述 | 90 | -------| ---- |:--------------- 91 | targetOS | string | 目标操作系统 (-T). eg. `linux` `win64` 92 | targetCPU |string| 目标CPU族 (-P). eg. `x86_64` `i386` 93 | customOptions|string []| 自定义编译选项. 94 | libPath|string[]|库搜索路径.(-Fl) 95 | outputFile| string| 目标文件名称.(-o) 96 | unitOutputDir| string|单元文件输出路径.(-FU) 97 | optimizationLevel| number|代码优化级别 (-O) 98 | searchPath| string[]|单元文件搜索路径.(-Fu) 99 | syntaxMode| string|语法模式 (-M {$mode}) 100 | forceRebuild| boolean|强制更新所有单元文件并编译.(-B) 101 | msgIgnore|number[]|指定编译时哪些消息不需要显示.(-vmxxx) 102 | 103 | 配置示例: 104 | ~~~ json 105 | { 106 | "version": "2.0.0", 107 | "tasks": [ 108 | { 109 | "label": "debug", 110 | "file": "main.lpr", 111 | "type": "fpc", 112 | "buildOption": { 113 | "unitOutputDir": "./out", 114 | "customOptions": [ 115 | "-dDEBUG", 116 | "-gw2" 117 | ] 118 | } 119 | } 120 | ] 121 | } 122 | ~~~ 123 | 124 | # 致谢 125 | ## 语法高亮 126 | 127 | 语法文件来自于 https://github.com/maresmar/ST-Pascal 128 | 129 | ## 格式化 130 | 131 | 修改自 https://github.com/git-bee/jcf-cli 132 | 133 | ## Pascal-language-server 134 | 135 | 修改自 136 | https://github.com/genericptr/pascal-language-server 137 | https://github.com/arjanadriaanse/pascal-language-server 138 | 139 | # 发布说明 140 | 141 | [查看更新记录](CHANGELOG.md) 142 | 143 | 144 | -------------------------------------------------------------------------------- /bin/aarch64-linux/jcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/aarch64-linux/jcf -------------------------------------------------------------------------------- /bin/aarch64-linux/pasls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/aarch64-linux/pasls -------------------------------------------------------------------------------- /bin/jcfsettings.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2.44 4 | 44832.7011022801 5 | format settings for use with Lazarus 6 | True 7 | 8 | False 9 | 1 10 | True 11 | True 12 | True 13 | True 14 | 15 | 16 | 0 17 | True 18 | False 19 | Sender 20 | dpr,lpr,pas,pp 21 | 22 | 23 | 2 24 | 0 25 | False 26 | False 27 | 2 28 | True 29 | False 30 | True 31 | True 32 | True 33 | True 34 | False 35 | True 36 | False 37 | False 38 | 39 | 40 | True 41 | False 42 | 2 43 | 2 44 | True 45 | False 46 | 0 47 | 0 48 | 0 49 | 0 50 | 0 51 | 0 52 | 0 53 | 0 54 | 0 55 | 2 56 | True 57 | 0 58 | False 59 | False 60 | False 61 | False 62 | False 63 | False 64 | 65 | 66 | 2 67 | 90 68 | 1 69 | True 70 | True 71 | False 72 | False 73 | True 74 | True 75 | True 76 | True 77 | True 78 | True 79 | True 80 | 1 81 | 0 82 | 83 | 1 84 | 1 85 | 1 86 | 0 87 | 0 88 | 0 89 | 1 90 | 0 91 | 1 92 | 0 93 | 1 94 | 1 95 | 0 96 | 1 97 | 0 98 | True 99 | 4 100 | 1 101 | 1 102 | 103 | 104 | True 105 | True 106 | 107 | 108 | True 109 | 1 110 | 1 111 | 1 112 | 1 113 | 1 114 | 115 | 116 | True 117 | 118 | 119 | 120 | True 121 | ActivePage,AnsiCompareStr,AnsiCompareText,AnsiUpperCase,AsBoolean,AsDateTime,AsFloat,AsInteger,Assign,AsString,AsVariant,BeginDrag,Buttons,Caption,Checked,Classes,ClassName,Clear,Close,Components,Controls,Count,Create,Data,Dec,Delete,Destroy,Dialogs,Enabled,EndDrag,EOF,Exception,Execute,False,FieldByName,First,Forms,Free,FreeAndNil,GetFirstChild,Graphics,Height,idAbort,idCancel,idIgnore,IDispatch,idNo,idOk,idRetry,idYes,Inc,Initialize,IntToStr,ItemIndex,IUnknown,Lines,Math,MaxValue,mbAbort,mbAll,mbCancel,mbHelp,mbIgnore,mbNo,mbOK,mbRetry,mbYes,mbYesToAll,Messages,MinValue,mnNoToAll,mrAbort,mrAll,mrCancel,mrIgnore,mrNo,mrNone,mrNoToAll,mrOk,mrRetry,mrYes,mrYesToAll,mtConfirmation,mtCustom,mtError,mtInformation,mtWarning,Name,Next,Open,Ord,ParamStr,PChar,Perform,ProcessMessages,Read,ReadOnly,RecordCount,Register,Release,Result,Sender,SetFocus,Show,ShowMessage,Source,StdCtrls,StrToInt,SysUtils,TAutoObject,TButton,TComponent,TDataModule,Text,TForm,TFrame,TList,TNotifyEvent,TObject,TObjectList,TPageControl,TPersistent,True,TStringList,TStrings,TTabSheet,Unassigned,Value,Visible,WideString,Width,Windows,Write 122 | 123 | 124 | True 125 | False,Name,nil,PChar,read,ReadOnly,True,WideString,write 126 | 127 | 128 | True 129 | ActnColorMaps,ActnCtrls,ActnList,ActnMan,ActnMenus,ActnPopup,ActnRes,ADOConst,ADODB,ADOInt,AppEvnts,AxCtrls,BandActn,bdeconst,bdemts,Buttons,CheckLst,Classes,Clipbrd.pas,CmAdmCtl,ComCtrls,ComStrs,Consts,Controls,CtlConsts,CtlPanel,CustomizeDlg,DataBkr,DB,DBActns,dbcgrids,DBClient,DBClientActnRes,DBClientActns,DBCommon,DBConnAdmin,DBConsts,DBCtrls,DbExcept,DBGrids,DBLocal,DBLocalI,DBLogDlg,dblookup,DBOleCtl,DBPWDlg,DBTables,DBXpress,DdeMan,Dialogs,DrTable,DSIntf,ExtActns,ExtCtrls,ExtDlgs,FileCtrl,FMTBcd,Forms,Graphics,GraphUtil,Grids,HTTPIntr,IB,IBBlob,IBCustomDataSet,IBDatabase,IBDatabaseInfo,IBDCLConst,IBErrorCodes,IBEvents,IBExternals,IBExtract,IBGeneratorEditor,IBHeader,IBIntf,IBQuery,IBRestoreEditor,IBSecurityEditor,IBServiceEditor,IBSQL,IBSQLMonitor,IBStoredProc,IBTable,IBUpdateSQL,IBUtils,IBXConst,ImgList,Jcl8087,JclAbstractContainers,JclAlgorithms,JclAnsiStrings,JclAppInst,JclArrayLists,JclArraySets,JclBase,JclBinaryTrees,JclBorlandTools,JclCIL,JclCLR,JclCOM,JclComplex,JclCompression,JclConsole,JclContainerIntf,JclCounter,JclDateTime,JclDebug,JclDotNet,JclEDI,JclEDISEF,JclEDITranslators,JclEDIXML,JclEDI_ANSIX12,JclEDI_ANSIX12_Ext,JclEDI_UNEDIFACT,JclEDI_UNEDIFACT_Ext,JclExprEval,JclFileUtils,JclFont,JclGraphics,JclGraphUtils,JclHashMaps,JclHashSets,JclHookExcept,JclIniFiles,JclLANMan,JclLinkedLists,JclLocales,JclLogic,JclMapi,JclMath,JclMetadata,JclMIDI,JclMime,JclMiscel,JclMsdosSys,JclMultimedia,JclNTFS,JclPCRE,JclPeImage,JclPrint,JclQGraphics,JclQGraphUtils,JclQueues,JclRegistry,JclResources,JclRTTI,JclSchedule,JclSecurity,JclShell,JclSimpleXml,JclStacks,JclStatistics,JclStreams,JclStrHashMap,JclStringLists,JclStrings,JclStructStorage,JclSvcCtrl,JclSynch,JclSysInfo,JclSysUtils,JclTask,JclTD32,JclUnicode,JclUnitConv,JclUnitVersioning,JclUnitVersioningProviders,JclValidation,JclVectors,JclWideFormat,JclWideStrings,JclWin32,JclWin32Ex,JclWinMIDI,ListActns,Mask,MConnect,Menus,Midas,MidasCon,MidConst,MPlayer,MtsRdm,Mxconsts,ObjBrkr,OleAuto,OleConst,OleCtnrs,OleCtrls,OleDB,OleServer,Outline,Printers,Provider,recerror,ScktCnst,ScktComp,ScktMain,SConnect,ShadowWnd,SimpleDS,SMINTF,SqlConst,SqlExpr,SqlTimSt,StdActnMenus,StdActns,StdCtrls,StdStyleActnCtrls,SvcMgr,SysUtils,TabNotBk,Tabs,TConnect,Themes,ToolWin,ValEdit,VDBConsts,WinHelpViewer,XPActnCtrls,XPMan,XPStyleActnCtrls 130 | 131 | 132 | 0 133 | 1 134 | True 135 | True 136 | 7 137 | True 138 | 15 139 | 140 | 141 | True 142 | MSWINDOWS 143 | 144 | 145 | 146 | False 147 | False 148 | False 149 | False 150 | False 151 | False 152 | False 153 | 2 154 | 60 155 | 5 156 | 5 157 | 0 158 | 159 | 160 | False 161 | 162 | 163 | 164 | False 165 | False 166 | False 167 | False 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 1 176 | True 177 | False 178 | False 179 | False 180 | False 181 | False 182 | 0 183 | False 184 | 185 | 186 | -------------------------------------------------------------------------------- /bin/win32/jcf.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/win32/jcf.exe -------------------------------------------------------------------------------- /bin/win32/pasls.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/win32/pasls.exe -------------------------------------------------------------------------------- /bin/x86_64-darwin/jcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/x86_64-darwin/jcf -------------------------------------------------------------------------------- /bin/x86_64-darwin/pasls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/x86_64-darwin/pasls -------------------------------------------------------------------------------- /bin/x86_64-linux/jcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/x86_64-linux/jcf -------------------------------------------------------------------------------- /bin/x86_64-linux/pasls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/bin/x86_64-linux/pasls -------------------------------------------------------------------------------- /images/doc/code-snippets.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/images/doc/code-snippets.gif -------------------------------------------------------------------------------- /images/doc/documentsymbol.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/images/doc/documentsymbol.gif -------------------------------------------------------------------------------- /images/doc/format.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/images/doc/format.gif -------------------------------------------------------------------------------- /images/doc/fpctoolkit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/images/doc/fpctoolkit.gif -------------------------------------------------------------------------------- /images/doc/quickfix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/images/doc/quickfix.gif -------------------------------------------------------------------------------- /images/icon-link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/images/logo.png -------------------------------------------------------------------------------- /images/pascal-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolchyni/fpctoolkit/bd55429c1e47770fa67c5ce4baa768daf1c1f80b/images/pascal-project.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fpctoolkit", 3 | "displayName": "FreePascal Toolkit", 4 | "description": "Free pascal compile and build.", 5 | "version": "1.1.9", 6 | "engines": { 7 | "vscode": "^1.44.0" 8 | }, 9 | "icon": "images/logo.png", 10 | "categories": [ 11 | "Programming Languages" 12 | ], 13 | "publisher": "coolchyni", 14 | "author": "coolchyni ", 15 | "license": "MIT", 16 | "keywords": [ 17 | "free", 18 | "pascal", 19 | "freepascal", 20 | "fpc", 21 | "lazarus", 22 | "objectpascal", 23 | "delphi" 24 | ], 25 | "private": true, 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/coolchyni/fpctoolkit.git" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/coolchyni/fpctoolkit/issues" 32 | }, 33 | "activationEvents": [ 34 | "onView:FpcProjectExplorer", 35 | "onLanguage:objectpascal" 36 | ], 37 | "main": "./out/extension.js", 38 | "contributes": { 39 | "languages": [ 40 | { 41 | "id": "objectpascal", 42 | "aliases": [ 43 | "Object-Pascal" 44 | ], 45 | "extensions": [ 46 | ".pas", 47 | ".pp", 48 | ".lpr", 49 | ".inc", 50 | ".p", 51 | ".dfm", 52 | ".fmx", 53 | ".dpr", 54 | ".dpk", 55 | ".lfm", 56 | ".dpr", 57 | ".lpr" 58 | ], 59 | "configuration": "./pascal-configuration.json" 60 | }, 61 | { 62 | "id": "pascal", 63 | "configuration": "./pascal-configuration.json" 64 | } 65 | ], 66 | "grammars": [ 67 | { 68 | "language": "objectpascal", 69 | "scopeName": "source.pascal", 70 | "path": "./syntaxes/fpc.tmLanguage" 71 | }, 72 | { 73 | "language": "pascal", 74 | "scopeName": "source.pascal", 75 | "path": "./syntaxes/fpc.tmLanguage" 76 | } 77 | ], 78 | "snippets": [ 79 | { 80 | "language": "objectpascal", 81 | "path": "./snippets/pascal.json" 82 | }, 83 | { 84 | "language": "pascal", 85 | "path": "./snippets/pascal.json" 86 | } 87 | ], 88 | "commands": [ 89 | { 90 | "command": "fpctoolkit.project.newproject", 91 | "title": "Create new Fpc Project" 92 | }, 93 | { 94 | "command": "fpctoolkit.project.build", 95 | "title": "%project.build%", 96 | "icon": "$(play)" 97 | }, 98 | { 99 | "command": "fpctoolkit.project.rebuild", 100 | "title": "%project.rebuild%" 101 | }, 102 | { 103 | "command": "fpctoolkit.project.clean", 104 | "title": "%project.clear%" 105 | }, 106 | { 107 | "command": "fpctoolkit.project.opensetting", 108 | "title": "%project.open%" 109 | }, 110 | { 111 | "command": "fpctoolkit.project.add", 112 | "title": "%project.newconfig%" 113 | }, 114 | { 115 | "command": "fpctoolkit.project.setdefault", 116 | "title": "%project.setdefault%" 117 | } 118 | ], 119 | "keybindings": [ 120 | { 121 | "key": "ctrl+shift+down", 122 | "command": "editor.action.goToImplementation", 123 | "when": "editorHasImplementationProvider && editorTextFocus && !isInEmbeddedEditor" 124 | }, 125 | { 126 | "key": "ctrl+shift+up", 127 | "command": "editor.action.goToImplementation", 128 | "when": "editorHasImplementationProvider && editorTextFocus && !isInEmbeddedEditor" 129 | }, 130 | { 131 | "key": "ctrl+shift+c", 132 | "command": "fpctoolkit.code.complete", 133 | "when": "editorTextFocus && !isInEmbeddedEditor" 134 | } 135 | ], 136 | "taskDefinitions": [ 137 | { 138 | "type": "fpc", 139 | "required": [ 140 | "file" 141 | ], 142 | "properties": { 143 | "file": { 144 | "type": "string", 145 | "description": "%task.file%" 146 | }, 147 | "cwd": { 148 | "type": "string", 149 | "description": "%task.cwd%" 150 | }, 151 | "cleanExt": { 152 | "type": "string", 153 | "description": "%task.cleanExt%" 154 | }, 155 | "inherited":{ 156 | "type":"string", 157 | "description": "%task.inherited%" 158 | }, 159 | "windows": { 160 | "type": "object", 161 | "properties": { 162 | "customOptions": { 163 | "type": "array", 164 | "items": { 165 | "type": "string" 166 | }, 167 | "description": "%task.buildOption.customOptions%" 168 | } 169 | } 170 | }, 171 | "linux": { 172 | "type": "object", 173 | "properties": { 174 | "customOptions": { 175 | "type": "array", 176 | "items": { 177 | "type": "string" 178 | }, 179 | "description": "%task.buildOption.customOptions%" 180 | } 181 | } 182 | }, 183 | "osx": { 184 | "type": "object", 185 | "properties": { 186 | "customOptions": { 187 | "type": "array", 188 | "items": { 189 | "type": "string" 190 | }, 191 | "description": "%task.buildOption.customOptions%" 192 | } 193 | } 194 | }, 195 | "buildEvent":{ 196 | "type":"object", 197 | "description": "Event to run command." , 198 | "properties": { 199 | "before_build":{ 200 | "type":"array", 201 | "description": "Run commands before build.", 202 | "items": { 203 | "type":"string" 204 | } 205 | }, 206 | "after_build_success":{ 207 | "type":"array", 208 | "description": "Run commands after build success.", 209 | "items": { 210 | "type":"string" 211 | } 212 | }, 213 | "after_build_failure":{ 214 | "type":"array", 215 | "description": "Run commands after build failure.", 216 | "items": { 217 | "type":"string" 218 | } 219 | } 220 | } 221 | }, 222 | "buildOption": { 223 | "type": "object", 224 | "properties": { 225 | "targetOS": { 226 | "type": "string", 227 | "description": "%task.buildOption.targetOS%", 228 | "examples": [ 229 | "linux", 230 | "win32", 231 | "win64", 232 | "Darwin" 233 | ] 234 | }, 235 | "targetCPU": { 236 | "type": "string", 237 | "description": "%task.buildOption.targetCPU%", 238 | "examples": [ 239 | "x86_64", 240 | "aarch64", 241 | "i386" 242 | ] 243 | }, 244 | "searchPath": { 245 | "type": "array", 246 | "description": "%task.buildOption.searchPath%", 247 | "items": { 248 | "type": "string" 249 | } 250 | }, 251 | "libPath": { 252 | "type": "array", 253 | "description": "%task.buildOption.libPath%", 254 | "items": { 255 | "type": "string" 256 | } 257 | }, 258 | "unitOutputDir": { 259 | "type": "string", 260 | "description": "%task.buildOption.unitOutputDir%" 261 | }, 262 | "outputFile": { 263 | "type": "string", 264 | "description": "%task.buildOption.outputFile%" 265 | }, 266 | "syntaxMode": { 267 | "type": "string", 268 | "description": "%task.buildOption.syntaxMode%", 269 | "default": "ObjFPC", 270 | "examples": [ 271 | "fpc", 272 | "Delphi", 273 | "DelphiUnicode", 274 | "ObjFPC" 275 | ] 276 | }, 277 | "optimizationLevel": { 278 | "type": "number", 279 | "description": "%task.buildOption.optimizationLevel%", 280 | "enum": [ 281 | 0, 282 | 1, 283 | 2, 284 | 3, 285 | 4 286 | ] 287 | }, 288 | "forceRebuild":{ 289 | "type":"boolean", 290 | "description": "%task.buildOption.forceRebuild%", 291 | "default":false 292 | }, 293 | "msgIgnore":{ 294 | "type":"array", 295 | "items": { 296 | "type":"number" 297 | }, 298 | "description": "%task.buildOption.msgIgnore%" 299 | }, 300 | "customOptions": { 301 | "type": "array", 302 | "items": { 303 | "type": "string" 304 | }, 305 | "description": "%task.buildOption.customOptions%" 306 | } 307 | } 308 | } 309 | } 310 | } 311 | ], 312 | "menus": { 313 | "view/item/context": [ 314 | { 315 | "command": "fpctoolkit.project.build", 316 | "when": "view == FpcProjectExplorer && viewItem==fpcbuild", 317 | "group": "fpcproject@1" 318 | }, 319 | { 320 | "command": "fpctoolkit.project.rebuild", 321 | "when": "view == FpcProjectExplorer && viewItem==fpcbuild", 322 | "group": "fpcproject@2" 323 | }, 324 | { 325 | "command": "fpctoolkit.project.clean", 326 | "when": "view == FpcProjectExplorer && viewItem==fpcbuild", 327 | "group": "fpcproject@3" 328 | }, 329 | { 330 | "command": "fpctoolkit.project.setdefault", 331 | "when": "view == FpcProjectExplorer && viewItem==fpcbuild", 332 | "group": "fpcprojectcfg@4" 333 | }, 334 | { 335 | "command": "fpctoolkit.project.add", 336 | "when": "view == FpcProjectExplorer && viewItem==fpcproject", 337 | "group": "fpcproject@0" 338 | }, 339 | { 340 | "command": "fpctoolkit.project.build", 341 | "when": "view == FpcProjectExplorer && viewItem==fpcbuild", 342 | "group": "inline" 343 | } 344 | 345 | ] 346 | }, 347 | "configuration": [ 348 | { 349 | "title": "FpcToolkit", 350 | "properties": { 351 | "fpctoolkit.searchPath": { 352 | "type": "array", 353 | "description": "%config.searchPath%", 354 | "items": { 355 | "type": "string" 356 | } 357 | }, 358 | "fpctoolkit.libPath": { 359 | "type": "array", 360 | "description": "%config.libPath%", 361 | "items": { 362 | "type": "string" 363 | } 364 | }, 365 | "fpctoolkit.customOptions": { 366 | "type": "array", 367 | "items": { 368 | "type": "string" 369 | }, 370 | "description": "%config.customOptions%" 371 | }, 372 | "fpctoolkit.env.PP": { 373 | "type": "string", 374 | "markdownDescription": "%config.env.PP%" 375 | }, 376 | "fpctoolkit.env.FPCDIR": { 377 | "type": "string", 378 | "markdownDescription": "%config.env.FPCDIR%" 379 | }, 380 | "fpctoolkit.env.LAZARUSDIR": { 381 | "type": "string", 382 | "markdownDescription": "%config.env.LAZARUSDIR%" 383 | }, 384 | "fpctoolkit.env.FPCTARGET": { 385 | "type": "string", 386 | "markdownDescription": "%config.env.FPCTARGET%", 387 | "examples": [ 388 | "linux", 389 | "win32", 390 | "win64", 391 | "Darwin" 392 | ] 393 | }, 394 | "fpctoolkit.env.FPCTARGETCPU": { 395 | "type": "string", 396 | "markdownDescription": "%config.env.FPCTARGETCPU%", 397 | "examples": [ 398 | "x86_64", 399 | "aarch64", 400 | "i386" 401 | ] 402 | }, 403 | "fpctoolkit.format.tabsize": { 404 | "type": "number", 405 | "default": 2, 406 | "markdownDescription": "%config.format.tabsize%" 407 | }, 408 | "fpctoolkit.pasls.path": { 409 | "type": "string", 410 | "description": "%config.pasls.path%" 411 | }, 412 | "fpctoolkit.format.enabled": { 413 | "type": "boolean", 414 | "default":"true", 415 | "description": "%config.format.enabled%" 416 | }, 417 | "fpctoolkit.format.cfgpath": { 418 | "type": "string", 419 | "description": "%config.format.cfgpath%" 420 | } 421 | 422 | } 423 | }, 424 | { 425 | "title": "FpcToolkit LanguageServer", 426 | "properties": { 427 | "fpctoolkit.lsp.trace.server": { 428 | "scope": "window", 429 | "type": "string", 430 | "enum": [ 431 | "off", 432 | "messages", 433 | "verbose" 434 | ], 435 | "default": "off", 436 | "description": "%lsp.trace.server%" 437 | }, 438 | "fpctoolkit.lsp.initializationOptions.program": { 439 | "type": "string", 440 | "description": "%lsp.initializationOptions.program%" 441 | }, 442 | "fpctoolkit.lsp.initializationOptions.overloadPolicy": { 443 | "type": "number", 444 | "scope": "application", 445 | "default": 3, 446 | "enum": [ 447 | 1, 448 | 2, 449 | 3 450 | ], 451 | "enumDescriptions": [ 452 | "%lsp.enum.overloadPolicy_1%", 453 | "%lsp.enum.overloadPolicy_2%", 454 | "%lsp.enum.overloadPolicy_3%" 455 | ], 456 | "description": "%lsp.initializationOptions.overloadPolicy%" 457 | }, 458 | "fpctoolkit.lsp.initializationOptions.maximumCompletions": { 459 | "type": "number", 460 | "default": 50, 461 | "markdownDescription": "%lsp.initializationOptions.maximumCompletions%" 462 | }, 463 | "fpctoolkit.lsp.initializationOptions.insertCompletionsAsSnippets": { 464 | "type": "boolean", 465 | "default": false, 466 | "description": "%lsp.initializationOptions.insertCompletionsAsSnippets%" 467 | }, 468 | "fpctoolkit.lsp.initializationOptions.insertCompletionProcedureBrackets": { 469 | "type": "boolean", 470 | "default": false, 471 | "description": "%lsp.initializationOptions.insertCompletionProcedureBrackets%" 472 | }, 473 | "fpctoolkit.lsp.initializationOptions.includeWorkspaceFoldersAsUnitPaths": { 474 | "type": "boolean", 475 | "default": true, 476 | "description": "%lsp.initializationOptions.includeWorkspaceFoldersAsUnitPaths%" 477 | }, 478 | "fpctoolkit.lsp.initializationOptions.includeWorkspaceFoldersAsIncludePaths": { 479 | "type": "boolean", 480 | "default": true, 481 | "description": "%lsp.initializationOptions.includeWorkspaceFoldersAsIncludePaths%" 482 | }, 483 | "fpctoolkit.lsp.initializationOptions.checkSyntax": { 484 | "type": "boolean", 485 | "scope": "application", 486 | "default": false, 487 | "description": "%lsp.initializationOptions.checkSyntax%" 488 | }, 489 | "fpctoolkit.lsp.initializationOptions.publishDiagnostics": { 490 | "type": "boolean", 491 | "scope": "application", 492 | "default": false, 493 | "description": "%lsp.initializationOptions.publishDiagnostics%" 494 | }, 495 | "fpctoolkit.lsp.initializationOptions.workspaceSymbols": { 496 | "type": "boolean", 497 | "default": false, 498 | "description": "%lsp.initializationOptions.workspaceSymbols%" 499 | }, 500 | "fpctoolkit.lsp.initializationOptions.documentSymbols": { 501 | "type": "boolean", 502 | "default": true, 503 | "description": "%lsp.initializationOptions.documentSymbols%" 504 | }, 505 | "fpctoolkit.lsp.initializationOptions.minimalisticCompletions": { 506 | "type": "boolean", 507 | "default": false, 508 | "description": "%lsp.initializationOptions.minimalisticCompletions%" 509 | }, 510 | "fpctoolkit.lsp.initializationOptions.showSyntaxErrors": { 511 | "type": "boolean", 512 | "default": true, 513 | "markdownDescription": "%lsp.initializationOptions.showSyntaxErrors%" 514 | } 515 | } 516 | } 517 | ], 518 | "views": { 519 | "explorer": [ 520 | { 521 | "id": "FpcProjectExplorer", 522 | "name": "FPC Projects" 523 | } 524 | ] 525 | }, 526 | "viewsWelcome": [ 527 | { 528 | "view": "FpcProjectExplorer", 529 | "contents": "%views.welcome%", 530 | "when": "!workspace.workspaceFolders" 531 | } 532 | ], 533 | "problemMatchers": [ 534 | { 535 | "name": "fpc", 536 | "owner": "external", 537 | "pattern": [ 538 | { 539 | "regexp": "Compiling ([^\\s].*(p|pp|pas|lpr|dpr|inc))$", 540 | "file": 1 541 | }, 542 | { 543 | "regexp": "^([\\w]+\\.(p|pp|pas|lpr|dpr|inc))\\((\\d+)\\,(\\d+)\\)\\s(Fatal|Error|Warning|Note):(.*)", 544 | "line": 3, 545 | "column": 4, 546 | "severity": 5, 547 | "message": 6, 548 | "loop": true 549 | } 550 | ] 551 | } 552 | ] 553 | }, 554 | "scripts": { 555 | "compile": "tsc -p ./", 556 | "lint": "eslint src --ext ts", 557 | "watch": "tsc -watch -p ./", 558 | "package": "vsce package", 559 | "publish": "vsce publish", 560 | "vscode:prepublish": "npm run -S esbuild-base -- --minify", 561 | "esbuild-base": "rimraf out && esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node", 562 | "esbuild": "npm run -S esbuild-base -- --sourcemap", 563 | "esbuild-watch": "npm run -S esbuild-base -- --sourcemap --watch" 564 | }, 565 | "dependencies": { 566 | "@types/fs-extra": "9.0.2", 567 | "fs-extra": "9.0.1", 568 | "tsc": "^2.0.4", 569 | "vscode-languageclient": "^8.0.1", 570 | "vscode-nls": "^3.2.5" 571 | }, 572 | "devDependencies": { 573 | "@types/glob": "^7.2.0", 574 | "@types/mocha": "^7.0.2", 575 | "@types/node": "^13.13.52", 576 | "@types/vscode": "^1.44.0", 577 | "@typescript-eslint/eslint-plugin": "^5.28.0", 578 | "@typescript-eslint/parser": "^5.28.0", 579 | "esbuild": "^0.14.23", 580 | "eslint": "^8.10.0", 581 | "glob": "^7.2.0", 582 | "mocha": "^9.2.1", 583 | "rimraf": "^3.0.2", 584 | "typescript": "^3.9.10" 585 | }, 586 | "homepage": "https://github.com/coolchyni/fpctoolkit#readme" 587 | } 588 | -------------------------------------------------------------------------------- /package.nls.json: -------------------------------------------------------------------------------- 1 | { 2 | "project.build": "Build", 3 | "project.rebuild": "Clean up and build", 4 | "project.clear": "Clean up", 5 | "project.open": "Open", 6 | "project.newconfig": "New Build Config", 7 | "project.setdefault": "Set As Default", 8 | "task.file": "The project file of FPC. (.lpr,.dpr)", 9 | "task.cwd": "Current path. Use wrokspace root if null.", 10 | "task.cleanExt": "file extensions for clean file in unitOutputDir. use * for clear all file. default:(.o,.ppu,.lfm,.a,.or,.res)", 11 | "task.buildOption.targetOS": "Target OS (-T)", 12 | "task.buildOption.targetCPU": "Target cpu family (-P)", 13 | "task.buildOption.searchPath": "Searchpath for units and other system dependent things.(-Fu)", 14 | "task.buildOption.libPath": "Searchpath for libraries.(-Fl)", 15 | "task.buildOption.unitOutputDir": "Unit output directory.(-FU)", 16 | "task.buildOption.outputFile": "Target file name.(-o)", 17 | "task.buildOption.syntaxMode": "Syntax Mode (-M,{$mode})", 18 | "task.buildOption.optimizationLevel": "Optimization levels (-O)", 19 | "task.buildOption.customOptions": "Custom compile options for fpc.", 20 | "task.buildOption.forceRebuild": "Re-compile all used units, even if the unit sources didn’t change since the last compilation.(-B)", 21 | "task.buildOption.msgIgnore": "Is a list of messages numbers which should not be shown.(-vmxxx)", 22 | "task.inherited":"Task name inheried from.", 23 | "config.searchPath": "Searchpath for units.(-Fu)", 24 | "config.libPath": "Searchpath for libraries.(-Fl)", 25 | "config.customOptions": "Custom compile options for fpc.", 26 | "config.env.PP": "Path to compiler (i.e. `/usr/bin/fpc`, `/usr/bin/ppc386`)", 27 | "config.env.FPCDIR": "Path to FPC sources such as `/usr/local/share/fpcsrc`", 28 | "config.env.LAZARUSDIR": "Path to Lazarus sources as `/usr/local/share/lazsrc`", 29 | "config.env.FPCTARGET": "Target platform (`win32`,`win64`, `linux`, `darwin`)", 30 | "config.env.FPCTARGETCPU": "Target CPU such as `x86_64`", 31 | "config.pasls.path": "Pascal Language Server(pasls) file path.", 32 | "lsp.trace.server": "Traces the communication between VS Code and the language server.", 33 | "lsp.initializationOptions.program": "Path to the main program file for resolving references (if not available the path of the current document will be used)", 34 | "lsp.initializationOptions.overloadPolicy": "Policy which determines how overloaded document symbols are displayed", 35 | "lsp.initializationOptions.maximumCompletions": "Maximum number of completion items to be returned. If the threshold is reached then `CompletionList.isIncomplete = true`", 36 | "lsp.initializationOptions.insertCompletionsAsSnippets": "Procedure completions with parameters are inserted as snippets", 37 | "lsp.initializationOptions.insertCompletionProcedureBrackets": "Procedure completions with parameters (non-snippet) insert empty brackets (and insert as snippet)", 38 | "lsp.initializationOptions.includeWorkspaceFoldersAsUnitPaths": "Workspaces folders will be added to unit paths (i.e. -Fu)", 39 | "lsp.initializationOptions.includeWorkspaceFoldersAsIncludePaths": "Workspaces folders will be added to include paths (i.e. -Fi)", 40 | "lsp.initializationOptions.checkSyntax": "Syntax will be checked when file opens or saves", 41 | "lsp.initializationOptions.publishDiagnostics": "Syntax errors will be published as diagnostics", 42 | "lsp.initializationOptions.workspaceSymbols": "Enable workspace symbols", 43 | "lsp.initializationOptions.documentSymbols": "Enable document symbols", 44 | "lsp.initializationOptions.minimalisticCompletions": "Completions contain a minimal amount of extra information", 45 | "lsp.initializationOptions.showSyntaxErrors": "Syntax errors as shown in the UI with ‘window/showMessage’", 46 | "lsp.enum.overloadPolicy_1": "Duplicate function names appear in the list", 47 | "lsp.enum.overloadPolicy_2": "After the original definition ignore others", 48 | "lsp.enum.overloadPolicy_3": "Add a suffix which denotes the overload count", 49 | 50 | "views.welcome":"No fpc projects found.\n[Create New Project](command:fpctoolkit.project.newproject)", 51 | 52 | "config.format.tabsize": "Table space size.", 53 | "config.format.enabled": "Enable jedi formatter.", 54 | "config.format.cfgpath": "The path of jcfsettings.cfg." 55 | 56 | } -------------------------------------------------------------------------------- /package.nls.zh-CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "project.build": "构建项目", 3 | "project.rebuild": "清理和构建", 4 | "project.clear": "清理项目", 5 | "project.open": "打开", 6 | "project.newconfig": "创建新的配置", 7 | "project.setdefault": "设置为默认任务", 8 | "task.file": "Free Pascal 项目文件. (.lpr,.dpr)", 9 | "task.cwd": "当前工作目录. 如果不设置默认使用vscode工作目录.", 10 | "task.cleanExt": "指定执行清理项目时需要清除的文件名后缀. 输入* 表示清除所有文件. 默认(.o,.ppu,.lfm,.a,.or,.res)", 11 | "task.buildOption.targetOS": "目标操作系统 (-T)", 12 | "task.buildOption.targetCPU": "目标CPU族 (-P)", 13 | "task.buildOption.searchPath": "单元文件搜索路径.(-Fu)", 14 | "task.buildOption.libPath": "库搜索路径.(-Fl)", 15 | "task.buildOption.unitOutputDir": "单元文件输出路径.(-FU)", 16 | "task.buildOption.outputFile": "目标文件名称.(-o)", 17 | "task.buildOption.syntaxMode": "语法模式 (-M,{$mode})", 18 | "task.buildOption.optimizationLevel": "代码优化级别 (-O)", 19 | "task.buildOption.customOptions": "自定义编译选项.", 20 | "task.buildOption.forceRebuild": "强制更新所有单元文件并编译.(-B)", 21 | "task.buildOption.msgIgnore":"指定编译时哪些消息不需要显示.可以指定多个error,warn,note编号。(-vmxxx)", 22 | "task.inherited":"继承任务的名称.", 23 | "config.searchPath": "单元文件搜索路径.(-Fu)", 24 | "config.libPath": "库搜索路径.(-Fl)", 25 | "config.customOptions": "自定义选项.", 26 | "config.env.PP": "编译器位置 (i.e. `/usr/bin/fpc`, `/usr/bin/ppc386`)", 27 | "config.env.FPCDIR": "Free Pascal 源代码位置 如:`/usr/local/share/fpcsrc`", 28 | "config.env.LAZARUSDIR": "Lazarus 源代码位置 如:`/usr/local/share/lazsrc`", 29 | "config.env.FPCTARGET": "目标操作系统 如: (`win32`,`win64`, `linux`, `darwin`)", 30 | "config.env.FPCTARGETCPU": "目标CPU族 如: `x86_64`", 31 | "config.pasls.path": "Pascal Language Server(pasls) 文件位置.", 32 | "lsp.trace.server": "跟踪 VS Code 和 pascal language server之间的通讯信息.", 33 | "lsp.initializationOptions.program": "主程序文件.如果未指定,则使用当前文件.", 34 | "lsp.initializationOptions.overloadPolicy": "指定重复的函数或定义如何显示", 35 | "lsp.initializationOptions.maximumCompletions": "自动代码提示显示的最大数量", 36 | "lsp.initializationOptions.insertCompletionsAsSnippets": "函数或过程参数自动变成模版插入", 37 | "lsp.initializationOptions.insertCompletionProcedureBrackets": "有参数的过程或函数插入时自动忽略参数", 38 | "lsp.initializationOptions.includeWorkspaceFoldersAsUnitPaths": "将当前工作目录添加到单元文件搜索目录(i.e. -Fu)", 39 | "lsp.initializationOptions.includeWorkspaceFoldersAsIncludePaths": "将当前工作目录添加到 include 目录 (i.e. -Fi)", 40 | "lsp.initializationOptions.checkSyntax": "文件打开和保存时进行语法检查", 41 | "lsp.initializationOptions.publishDiagnostics": "语法错误作为诊断信息显示", 42 | "lsp.initializationOptions.workspaceSymbols": "允许显示工作目录的类,函数,过程...", 43 | "lsp.initializationOptions.documentSymbols": "允许显示当前文档的类,函数,过程...", 44 | "lsp.initializationOptions.minimalisticCompletions": "自动代码提示包含最少的信息", 45 | "lsp.initializationOptions.showSyntaxErrors": "弹窗显示语法错误提示 ‘window/showMessage’", 46 | "lsp.enum.overloadPolicy_1": "显示多个名称", 47 | "lsp.enum.overloadPolicy_2": "只显示第一个", 48 | "lsp.enum.overloadPolicy_3": "名称前添加编号", 49 | 50 | "views.welcome":"没有发现工程文件.\n[创建新项目](command:fpctoolkit.project.newproject)", 51 | "config.format.tabsize": "制表符(tab)转空格数.", 52 | "config.format.enabled": "启用源码格式化(使用Jedi).", 53 | "config.format.cfgpath": "格式化配置文件路径(jcfsettings.cfg)." 54 | } -------------------------------------------------------------------------------- /pascal-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//", 4 | "blockComment": [ "{", "}" ] 5 | }, 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | "autoClosingPairs": [ 12 | ["{", "}"], 13 | ["[", "]"], 14 | ["(", ")"], 15 | ["<", ">"], 16 | ["'", "'"] 17 | ], 18 | "surroundingPairs": [ 19 | ["{", "}"], 20 | ["[", "]"], 21 | ["(", ")"], 22 | ["<", ">"], 23 | ["'", "'"] 24 | ], 25 | "folding": { 26 | "markers": { 27 | "start": "^\\s*\\{\\$REGION(\\s\\'.*\\')?\\}", 28 | "end": "^\\s*\\{\\$ENDREGION\\}" 29 | } 30 | } 31 | 32 | 33 | 34 | } -------------------------------------------------------------------------------- /snippets/pascal.json: -------------------------------------------------------------------------------- 1 | { 2 | "array const":{ 3 | "prefix":"arrayc", 4 | "body":[ 5 | "array[${1:0}..${2:1}] of ${3:type} = ($4,$0);" 6 | ], 7 | "description":"array declaration(const)" 8 | }, 9 | "array var":{ 10 | "prefix":"array", 11 | "body":[ 12 | "array[${1:0}..${2:1}] of ${0:type};" 13 | ], 14 | "description":"array declaration(var)" 15 | }, 16 | "begin end": { 17 | "prefix": "begin", 18 | "body": [ 19 | "begin", 20 | "\t$0", 21 | "end;" 22 | ], 23 | "description": "Begin end" 24 | }, 25 | "case end": { 26 | "prefix": "case", 27 | "body": [ 28 | "case $1 of", 29 | "\t$0", 30 | "end;" 31 | ], 32 | "description": "case end" 33 | }, 34 | "class (no parts)": { 35 | "prefix": "classd", 36 | "body": [ 37 | "T$1 = class(${2:ancestor})", 38 | "\t$3", 39 | "end;" 40 | ], 41 | "description": "class (no parts)" 42 | }, 43 | "class (with Create/Destroy)": { 44 | "prefix": "classc", 45 | "body": [ 46 | "T${1:ClassName} = class(T${2:ancestor})", 47 | "private", 48 | "\t$0", 49 | "protected", 50 | "\t", 51 | "public", 52 | "\tconstructor Create; override;", 53 | "\tdestructor Destroy; override;", 54 | "published", 55 | "\t", 56 | "end;" 57 | ], 58 | "description": "class (with Create/Destroy)" 59 | }, 60 | "constructor Create": { 61 | "prefix": "Create", 62 | "body": [ 63 | "constructor Create(); ${1:override;}" 64 | ], 65 | "description": "constructor descendant" 66 | }, 67 | "destructor Destroy": { 68 | "prefix": "Destroy", 69 | "body": [ 70 | "destructor Destroy; override;$0" 71 | ], 72 | "description": "destructor" 73 | }, 74 | "Create object with finally": { 75 | "prefix": "CreateF", 76 | "body": [ 77 | "${1:ObjectName} := ${2:TObject}.Create($3);", 78 | "try", 79 | " $2", 80 | "finally", 81 | " ${1:ObjectName}.Free;", 82 | "end;" 83 | ], 84 | "description": "Create an object and free it in finally block" 85 | }, 86 | "else end": { 87 | "prefix": "else", 88 | "body": [ 89 | "else", 90 | "begin", 91 | "\t$0", 92 | "end;" 93 | ], 94 | "description": "else end" 95 | }, 96 | "enum": { 97 | "prefix": "enum", 98 | "body": [ 99 | "T${1:EnumName} = (${2:meOne}, $0);" 100 | ], 101 | "description": "enum" 102 | }, 103 | "for begin end": { 104 | "prefix": "for", 105 | "body": [ 106 | "for ${1:i} := ${2:0} to ${3:max} do", 107 | "begin", 108 | "\t$0", 109 | "end;" 110 | ], 111 | "description": "for begin end" 112 | }, 113 | "for in end": { 114 | "prefix": "forin", 115 | "body": [ 116 | "for ${1:MyElem} in ${2:MyList} do", 117 | "begin", 118 | "\t$0", 119 | "end;" 120 | ], 121 | "description": "for in end" 122 | }, 123 | "for downto": { 124 | "prefix": "ford", 125 | "body": [ 126 | "for ${1:i} := ${2:max} downto ${3:0} do", 127 | "begin", 128 | "\t$0", 129 | "end;" 130 | ], 131 | "description": "for downto" 132 | }, 133 | "for (no begin end)": { 134 | "prefix": "fors", 135 | "body": [ 136 | "for ${1:i} := ${2:0} to ${3:max} do", 137 | "\t$0" 138 | ], 139 | "description": "for (no begin end)" 140 | }, 141 | "function end": { 142 | "prefix": "function", 143 | "body": [ 144 | "function ${1:MyFunction}(${2}):${3};", 145 | "begin", 146 | "\t$0", 147 | "end;" 148 | ], 149 | "description": "function end" 150 | }, 151 | "if (no begin end)": { 152 | "prefix": "ifn", 153 | "body": [ 154 | "if ${1} then \t$0" 155 | ], 156 | "description": "if (no begin end)" 157 | }, 158 | "if end": { 159 | "prefix": "if", 160 | "body": [ 161 | "if ${1} then", 162 | "begin", 163 | "\t$0", 164 | "end;" 165 | ], 166 | "description": "if end" 167 | }, 168 | "if else (no begin end)": { 169 | "prefix": "ifen", 170 | "body": [ 171 | "if ${1} then", 172 | "\t$2", 173 | "else", 174 | "\t$3" 175 | ], 176 | "description": "if else (no begin end)" 177 | }, 178 | "if else end": { 179 | "prefix": "ife", 180 | "body": [ 181 | "if ${1} then", 182 | "begin", 183 | "\t$2", 184 | "end", 185 | "else", 186 | "begin", 187 | "\t$3", 188 | "end;" 189 | ], 190 | "description": "if else end" 191 | }, 192 | "if not Assigned (no begin end)": { 193 | "prefix": "ifnass", 194 | "body": [ 195 | "if not Assigned(${1}) then", 196 | "\t${1} := T${1}.Create(${2});$0" 197 | ], 198 | "description": "if not Assigned (no begin end)" 199 | }, 200 | "if nil (no begin end)": { 201 | "prefix": "ifnil", 202 | "body": [ 203 | "if $1 = nil then", 204 | "\t$1 := T${2:ClassName}.Create($3);$0" 205 | ], 206 | "description": "if nil (no begin end)" 207 | }, 208 | "procedure end": { 209 | "prefix": "procedure", 210 | "body": [ 211 | "procedure ${1:MyProcedure}(${2});", 212 | "begin", 213 | "\t$0", 214 | "end;" 215 | ], 216 | "description": "procedure" 217 | }, 218 | "property getter": { 219 | "prefix": "prop", 220 | "body": [ 221 | "property ${1:name}: ${2:type} read Get${1} write Set${1};$0" 222 | ], 223 | "description": "property getter" 224 | }, 225 | "property field": { 226 | "prefix": "propf", 227 | "body": [ 228 | "property ${1:name}: ${2:type} read F${1:name} write F${1:name};$0" 229 | ], 230 | "description": "property field" 231 | }, 232 | "property read only field": { 233 | "prefix": "proprof", 234 | "body": [ 235 | "property ${1:name}: ${2:type} read F${1:name};$0" 236 | ], 237 | "description": "property read only field" 238 | }, 239 | "property read only field with func": { 240 | "prefix": "proprof", 241 | "body": [ 242 | "property ${1:name}: ${2:type} read F${1:name};$0" 243 | ], 244 | "description": "property read only field" 245 | }, 246 | 247 | "property get and set with function ": { 248 | "prefix": "property get and set with function", 249 | "body": [ 250 | "procedure Set${1:Name}(const Value: ${2:TType});", 251 | "function Get${1:Name}: ${2:TType};", 252 | "property ${1:Name}: ${2:TType} read Get${1:Name} write Set${1:Name};" 253 | ], 254 | "description": "property get and set with function" 255 | }, 256 | "property get with function": { 257 | "prefix": "property get with function", 258 | "body": [ 259 | "function Get${1:Name}: ${2:TType};", 260 | "property ${1:Name}: ${2:TType} read Get${1:Name};" 261 | ], 262 | "description": "property get with function" 263 | }, 264 | "raise": { 265 | "prefix": "raise", 266 | "body": [ 267 | "raise ${1:Exception}.Create('${2:Error Message}');$0" 268 | ], 269 | "description": "raise" 270 | }, 271 | "region": { 272 | "prefix": "region", 273 | "body": [ 274 | "{\\$REGION '${1:MyRegion}'}", 275 | "\t$0", 276 | "{\\$ENDREGION}" 277 | ], 278 | "description": "region" 279 | }, 280 | "repeat until": { 281 | "prefix": "repeat", 282 | "body": [ 283 | "repeat", 284 | "\t$0", 285 | "until (${1:True});" 286 | ], 287 | "description": "repeat until" 288 | }, 289 | 290 | "try finally": { 291 | "prefix": "tryf", 292 | "body": [ 293 | "try", 294 | "\t$0", 295 | "finally", 296 | "\t$1", 297 | "end;" 298 | ], 299 | "description": "try finally" 300 | }, 301 | "try except": { 302 | "prefix": "trye", 303 | "body": [ 304 | "try", 305 | "\t$0", 306 | "except", 307 | "\ton ${1:e}: ${2:Exception} do", 308 | "end;" 309 | ], 310 | "description": "try except" 311 | }, 312 | "finally end": { 313 | "prefix": "finally", 314 | "body": [ 315 | "finally", 316 | " $1", 317 | "end;" 318 | ], 319 | "description": "finally end" 320 | }, 321 | "except end": { 322 | "prefix": "except", 323 | "body": [ 324 | "except", 325 | " on E: Exception do", 326 | " begin", 327 | " $1", 328 | " end;", 329 | "end;" 330 | ], 331 | "description": "try except end" 332 | }, 333 | "try object finally": { 334 | "prefix": "trycf", 335 | "body": [ 336 | "${1:variable} := ${2:TComponent}.Create(${3});", 337 | "try", 338 | "\t$0", 339 | "finally", 340 | "\tFreeAndNil(${1:variable});", 341 | "end;" 342 | ], 343 | "description": "try object finally" 344 | }, 345 | "out": { 346 | "prefix": "out", 347 | "body": [ 348 | "out" 349 | ], 350 | "description": "out" 351 | }, 352 | "then": { 353 | "prefix": "then", 354 | "body": [ 355 | "then", 356 | "begin", 357 | " $1", 358 | "end;" 359 | ], 360 | "description": "then with begin end" 361 | }, 362 | "then else": { 363 | "prefix": "thene", 364 | "body": [ 365 | "then", 366 | "begin", 367 | " $1", 368 | "end", 369 | "else", 370 | "begin", 371 | " $2", 372 | "end;" 373 | ], 374 | "description": "then else with begin end" 375 | }, 376 | "while do": { 377 | "prefix": "while", 378 | "body": [ 379 | "while $1 do", 380 | "begin", 381 | " $2", 382 | "end;" 383 | ], 384 | "description": "while do" 385 | }, 386 | "do": { 387 | "prefix": "do", 388 | "body": [ 389 | "do", 390 | " $1" 391 | ], 392 | "description": "do" 393 | }, 394 | "until": { 395 | "prefix": "until", 396 | "body": [ 397 | "until ($1);" 398 | ], 399 | "description": "until" 400 | }, 401 | "private": { 402 | "prefix": "private", 403 | "body": [ 404 | "private" 405 | ], 406 | "description": "private" 407 | }, 408 | "protected": { 409 | "prefix": "protected", 410 | "body": [ 411 | "protected" 412 | ], 413 | "description": "protected" 414 | }, 415 | "public": { 416 | "prefix": "public", 417 | "body": [ 418 | "public" 419 | ], 420 | "description": "public" 421 | }, 422 | "published": { 423 | "prefix": "published", 424 | "body": [ 425 | "published" 426 | ], 427 | "description": "published" 428 | }, 429 | "strict private": { 430 | "prefix": "strict private", 431 | "body": [ 432 | "strict private" 433 | ], 434 | "description": "strict private" 435 | }, 436 | "strict protected": { 437 | "prefix": "strict protected", 438 | "body": [ 439 | "strict protected" 440 | ], 441 | "description": "strict protected" 442 | }, 443 | "class": { 444 | "prefix": "class", 445 | "body": [ 446 | "class" 447 | ], 448 | "description": "class" 449 | }, 450 | "record": { 451 | "prefix": "record", 452 | "body": [ 453 | "record" 454 | ], 455 | "description": "record" 456 | }, 457 | "interface": { 458 | "prefix": "interface", 459 | "body": [ 460 | "interface" 461 | ], 462 | "description": "interface" 463 | }, 464 | "implementation": { 465 | "prefix": "implementation", 466 | "body": [ 467 | "implementation" 468 | ], 469 | "description": "implementation" 470 | }, 471 | "class procedure": { 472 | "prefix": "class procedure", 473 | "body": [ 474 | "class procedure" 475 | ], 476 | "description": "class procedure" 477 | }, 478 | "class function": { 479 | "prefix": "class function", 480 | "body": [ 481 | "class function" 482 | ], 483 | "description": "class function" 484 | }, 485 | "cdecl": { 486 | "prefix": "cdecl", 487 | "body": [ 488 | "cdecl" 489 | ], 490 | "description": "cdecl" 491 | }, 492 | "stdcall": { 493 | "prefix": "stdcall", 494 | "body": [ 495 | "stdcall" 496 | ], 497 | "description": "stdcall" 498 | }, 499 | "external": { 500 | "prefix": "external", 501 | "body": [ 502 | "external" 503 | ], 504 | "description": "external" 505 | }, 506 | "static": { 507 | "prefix": "static", 508 | "body": [ 509 | "static" 510 | ], 511 | "description": "static" 512 | }, 513 | "virtual": { 514 | "prefix": "virtual", 515 | "body": [ 516 | "virtual" 517 | ], 518 | "description": "virtual" 519 | }, 520 | "override": { 521 | "prefix": "override", 522 | "body": [ 523 | "override" 524 | ], 525 | "description": "override" 526 | }, 527 | "reintroduce": { 528 | "prefix": "reintroduce", 529 | "body": [ 530 | "reintroduce" 531 | ], 532 | "description": "reintroduce" 533 | }, 534 | "overload": { 535 | "prefix": "overload", 536 | "body": [ 537 | "overload" 538 | ], 539 | "description": "overload" 540 | }, 541 | "mode": { 542 | "prefix": "mode", 543 | "body": [ 544 | "{\\$mode ${1|delphi,objfpc|}}{\\$H+}" 545 | ], 546 | "description": "{$mode }" 547 | }, 548 | 549 | 550 | "unit with class(ObjFPC)": { 551 | "prefix": "unit with class", 552 | "body": [ 553 | "unit $1;", 554 | "", 555 | "{\\$mode objfpc}{\\$H+}", 556 | "", 557 | "interface", 558 | "uses", 559 | "\tSysUtils, Classes;", 560 | "", 561 | "type", 562 | "\tT$1 = class(T${2:Object})", 563 | "\tprivate", 564 | "\t$0", 565 | "\tprotected", 566 | "\t\t", 567 | "\tpublic", 568 | "\t\tconstructor Create;", 569 | "\t\tdestructor Destroy; override;", 570 | "\tpublished", 571 | "\t\t", 572 | "end;", 573 | "", 574 | "implementation", 575 | "constructor T$1.Create;", 576 | "begin", 577 | "\tinherited Create;", 578 | "\t", 579 | "end;", 580 | "\t", 581 | "destructor T$1.Destroy;", 582 | "begin", 583 | "\tinherited Destroy;", 584 | "\t", 585 | "end;", 586 | "", 587 | "end." 588 | ], 589 | "description": "unit with class" 590 | }, 591 | "unit (FPC)": { 592 | "prefix": "unit", 593 | "body": [ 594 | "unit ${1:unit_name};", 595 | "", 596 | "{\\$mode objfpc}{\\$H+}", 597 | "", 598 | "interface", 599 | "\t", 600 | "uses", 601 | "\tSysUtils${2:, Classes};", 602 | "\t", 603 | "implementation", 604 | "\t", 605 | "$0", 606 | "\t", 607 | "end." 608 | ], 609 | "description": "unit template" 610 | }, 611 | "unit with class(Delphi)": { 612 | "prefix": "unit with class", 613 | "body": [ 614 | "unit $1;", 615 | "", 616 | "{\\$mode delphi}{\\$H+}", 617 | "", 618 | "interface", 619 | "uses", 620 | "\tSysUtils, Classes;", 621 | "", 622 | "type", 623 | "\tT$1 = class(T${2:Object})", 624 | "\tprivate", 625 | "\t$0", 626 | "\tprotected", 627 | "\t\t", 628 | "\tpublic", 629 | "\t\tconstructor Create;", 630 | "\t\tdestructor Destroy; override;", 631 | "\tpublished", 632 | "\t\t", 633 | "end;", 634 | "", 635 | "implementation", 636 | "constructor T$1.Create;", 637 | "begin", 638 | "\tinherited Create;", 639 | "\t", 640 | "end;", 641 | "\t", 642 | "destructor T$1.Destroy;", 643 | "begin", 644 | "\tinherited Destroy;", 645 | "\t", 646 | "end;", 647 | "", 648 | "end." 649 | ], 650 | "description": "unit with class" 651 | }, 652 | "unit (Delphi)": { 653 | "prefix": "unit", 654 | "body": [ 655 | "unit ${1:unit_name};", 656 | "", 657 | "{\\$mode delphi}{\\$H+}", 658 | "", 659 | "interface", 660 | "\t", 661 | "uses", 662 | "\tSysUtils${2:, Classes};", 663 | "\t", 664 | "implementation", 665 | "\t", 666 | "$0", 667 | "\t", 668 | "end." 669 | ], 670 | "description": "unit template" 671 | }, 672 | "specialize":{ 673 | "prefix":"specialize", 674 | "body":[ 675 | "specialize $0;" 676 | ], 677 | "description":"specialize declaration" 678 | } 679 | } -------------------------------------------------------------------------------- /src/commands.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { FpcItem } from './providers/project'; 3 | import * as fs from 'fs'; 4 | import * as fs2 from 'fs-extra'; 5 | import path = require('path'); 6 | import { BuildMode, FpcTask, FpcTaskDefinition, FpcTaskProvider, taskProvider } from './providers/task'; 7 | import { CompileOption } from './languageServer/options'; 8 | import { configuration } from './common/configuration' 9 | import { type } from 'os'; 10 | import { client } from './extension'; 11 | import { TextEditor, TextEditorEdit } from 'vscode'; 12 | 13 | 14 | export class FpcCommandManager { 15 | constructor(private workspaceRoot: string) { 16 | 17 | } 18 | registerAll(context: vscode.ExtensionContext) { 19 | context.subscriptions.push(vscode.commands.registerCommand('fpctoolkit.project.build', this.ProjectBuild)); 20 | context.subscriptions.push(vscode.commands.registerCommand('fpctoolkit.project.rebuild', this.ProjectReBuild)); 21 | context.subscriptions.push(vscode.commands.registerCommand('fpctoolkit.project.clean', this.projectClean)); 22 | context.subscriptions.push(vscode.commands.registerCommand('fpctoolkit.project.opensetting', this.ProjectOpen)); 23 | context.subscriptions.push(vscode.commands.registerCommand('fpctoolkit.project.newproject', this.ProjectNew)); 24 | context.subscriptions.push(vscode.commands.registerCommand('fpctoolkit.project.add', this.ProjectAdd)); 25 | context.subscriptions.push(vscode.commands.registerCommand('fpctoolkit.project.setdefault', this.projectSetDefault)); 26 | 27 | context.subscriptions.push(vscode.commands.registerTextEditorCommand('fpctoolkit.code.complete',this.CodeComplete)); 28 | } 29 | ProjectAdd = async (node: FpcItem) => { 30 | if (node.level === 0) { 31 | let config = vscode.workspace.getConfiguration('tasks', vscode.Uri.file(this.workspaceRoot)); 32 | let inp = await vscode.window.showQuickPick(['debug', 'release', 'other...'], { canPickMany: false }); 33 | if (!inp) { 34 | return; 35 | } 36 | let label: string | undefined; 37 | let customOption = '-dDEBUG'; 38 | let isDebug=false; 39 | switch (inp) { 40 | case 'debug': 41 | isDebug=true; 42 | label = 'debug'; 43 | break; 44 | case 'release': 45 | label = 'release'; 46 | customOption = '-dRELEASE'; 47 | break; 48 | 49 | default: 50 | label = await vscode.window.showInputBox({ prompt: 'Input build label:' }); 51 | 52 | break; 53 | } 54 | if (!label) { 55 | return; 56 | } 57 | let v = { 58 | "label": label, 59 | "file": node.label, 60 | "type": "fpc", 61 | "buildOption": { 62 | "syntaxMode": "ObjFPC", 63 | "unitOutputDir": "./out", 64 | "customOptions": [ 65 | customOption 66 | ] 67 | } 68 | }; 69 | if(isDebug){ 70 | v.buildOption.customOptions=[customOption,'-gw2']; 71 | } 72 | 73 | let tasks = config.tasks; 74 | if (tasks) { 75 | tasks.push(v); 76 | } else { 77 | tasks = [v]; 78 | } 79 | config.update( 80 | "tasks", 81 | tasks, 82 | vscode.ConfigurationTarget.WorkspaceFolder 83 | ); 84 | } 85 | 86 | }; 87 | ProjectBuild = async (node: FpcItem) => { 88 | if (node.level === 0) { 89 | 90 | } else { 91 | vscode.tasks.fetchTasks({ type: 'fpc' }).then((e) => { 92 | e.forEach((task) => { 93 | //vscode.window.showInformationMessage(task.name); 94 | if (task.name === node.label) { 95 | let newtask=taskProvider.taskMap.get(task.name); 96 | if(newtask){ 97 | (newtask as FpcTask).BuildMode=BuildMode.normal; 98 | } 99 | vscode.tasks.executeTask(task); 100 | 101 | return; 102 | } 103 | 104 | }); 105 | }); 106 | 107 | } 108 | 109 | }; 110 | 111 | ProjectReBuild = async (node: FpcItem) => { 112 | 113 | if (node.level === 0) { 114 | 115 | } else { 116 | await this.projectClean(node); 117 | this.ProjectBuild(node); 118 | 119 | // vscode.tasks.fetchTasks({ type: 'fpc' }).then((e) => { 120 | 121 | // for (const task of e) { 122 | // if (task.name === node.label) { 123 | // let newtask=taskProvider.taskMap.get(task.name); 124 | // if(newtask){ 125 | // (newtask as FpcTask).BuildMode=BuildMode.rebuild; 126 | // } 127 | 128 | // vscode.tasks.executeTask(task).then((e)=>{ 129 | // console.log(e.task.name); 130 | // }); 131 | 132 | // return; 133 | // } 134 | 135 | // } 136 | // }); 137 | 138 | } 139 | 140 | }; 141 | ProjectOpen = async (node?: FpcItem) => { 142 | 143 | let file = path.join(this.workspaceRoot, ".vscode", "tasks.json"); 144 | let doc = await vscode.workspace.openTextDocument(file); 145 | let te = await vscode.window.showTextDocument(doc, vscode.ViewColumn.One); 146 | 147 | }; 148 | ProjectNew = async () => { 149 | 150 | let s = `program main; 151 | {$mode objfpc}{$H+} 152 | uses 153 | classes,sysutils; 154 | begin 155 | 156 | end.`; 157 | 158 | let file = path.join(this.workspaceRoot, "main.lpr"); 159 | 160 | 161 | fs.writeFile(file, s, () => { 162 | let f = vscode.workspace.openTextDocument(file); 163 | f.then((doc) => { 164 | vscode.window.showTextDocument(doc, vscode.ViewColumn.One) 165 | .then((e: vscode.TextEditor) => { 166 | let pos = new vscode.Position(2, 4); 167 | e.selection = new vscode.Selection(pos, pos); 168 | }); 169 | 170 | }); 171 | 172 | }); 173 | 174 | let config = vscode.workspace.getConfiguration('tasks', vscode.Uri.file(this.workspaceRoot)); 175 | 176 | let v = { 177 | "label": "debug", 178 | "file": "main.lpr", 179 | "type": "fpc", 180 | "presentation": { 181 | "showReuseMessage": false, 182 | "clear": true, 183 | "revealProblems": "onProblem" 184 | }, 185 | "buildOption": { 186 | "unitOutputDir": "./out", 187 | "customOptions": [ 188 | "-dDEBUG" 189 | ] 190 | } 191 | }; 192 | let tasks = config.tasks; 193 | if (tasks) { 194 | tasks.push(v); 195 | } else { 196 | tasks = [v]; 197 | } 198 | config.update( 199 | "tasks", 200 | tasks, 201 | vscode.ConfigurationTarget.WorkspaceFolder 202 | ); 203 | 204 | }; 205 | projectClean = async (node: FpcItem) => { 206 | 207 | let definition = taskProvider.GetTaskDefinition(node.label); 208 | 209 | let dir = definition?.buildOption?.unitOutputDir; 210 | if (!dir) { return; } 211 | if (!path.isAbsolute(dir)) { 212 | 213 | if (definition?.cwd) { 214 | let cur_dir=definition.cwd; 215 | if(cur_dir.startsWith('./') || cur_dir.startsWith('.\\')){ 216 | cur_dir=path.join(this.workspaceRoot,definition.cwd); 217 | } 218 | dir = path.join(cur_dir, dir); 219 | } else { 220 | dir = path.join(this.workspaceRoot, dir); 221 | } 222 | } 223 | 224 | let cleanExt = definition?.cleanExt; 225 | if (fs.existsSync(dir)) { 226 | try { 227 | let exts = ['.o', '.ppu', '.lfm', '.a', '.or', '.res','.rsj','.obj']; 228 | let isall = false; 229 | if (cleanExt) { 230 | if ((cleanExt).trim() == '*') { 231 | isall = true; 232 | } 233 | let tmps = (cleanExt).split(','); 234 | for (const s of tmps) { 235 | exts.push(s); 236 | } 237 | } 238 | let files = fs.readdirSync(dir); 239 | for (let index = 0; index < files.length; index++) { 240 | let file = files[index].toLowerCase(); 241 | let ext = path.extname(file); 242 | 243 | if (isall || exts.includes(ext)) { 244 | try { 245 | fs2.removeSync(path.join(dir, file)); 246 | } catch { 247 | 248 | } 249 | 250 | } 251 | } 252 | 253 | } catch { 254 | 255 | } 256 | } 257 | }; 258 | 259 | projectSetDefault = async (node: FpcItem) => { 260 | let config = vscode.workspace.getConfiguration('tasks', vscode.Uri.file(this.workspaceRoot)); 261 | let tasks=config.tasks; 262 | for (const task of tasks) { 263 | if(task.label===node.label){ 264 | if(typeof(task.group)==='object'){ 265 | task.group.isDefault=true; 266 | }else{ 267 | task.group={kind:task.group,isDefault:true}; 268 | } 269 | client.restart(); 270 | }else{ 271 | if(typeof(task.group)==='object'){ 272 | task.group.isDefault=undefined; 273 | } 274 | } 275 | 276 | 277 | } 278 | config.update( 279 | "tasks", 280 | tasks, 281 | vscode.ConfigurationTarget.WorkspaceFolder 282 | ); 283 | } 284 | 285 | 286 | CodeComplete= async (textEditor: TextEditor, edit: TextEditorEdit) => { 287 | client.doCodeComplete(textEditor); 288 | 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/common/configuration.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConfigurationChangeEvent, Event, EventEmitter, workspace, 3 | WorkspaceConfiguration, ConfigurationTarget, Uri 4 | } from "vscode"; 5 | 6 | const extensionName = "fpctoolkit"; 7 | 8 | class Configuration 9 | { 10 | private configuration: WorkspaceConfiguration; 11 | private configurationWs: WorkspaceConfiguration; 12 | private _onDidChange = new EventEmitter(); 13 | 14 | 15 | // get onDidChange(): Event 16 | // { 17 | // return this._onDidChange.event; 18 | // } 19 | 20 | 21 | constructor() 22 | { 23 | this.configuration = workspace.getConfiguration(extensionName); 24 | this.configurationWs = workspace.getConfiguration(); 25 | workspace.onDidChangeConfiguration(this.onConfigurationChanged, this); 26 | } 27 | 28 | 29 | private onConfigurationChanged(event: ConfigurationChangeEvent) 30 | { 31 | if (event.affectsConfiguration(extensionName)) 32 | { 33 | this.configuration = workspace.getConfiguration(extensionName); 34 | this._onDidChange.fire(event); 35 | } 36 | } 37 | 38 | 39 | public get(key: string, defaultValue?: T): T 40 | { 41 | return this.configuration.get(key, defaultValue!); 42 | } 43 | 44 | 45 | /** 46 | * Include entire settings key. This is just workspace.getConfiguration(). 47 | * Example: 48 | * getGlobal("terminal.integrated.shell.windows", "") 49 | */ 50 | public getVs(key: string, defaultValue?: T): T 51 | { 52 | return this.configurationWs.get(key, defaultValue!); 53 | } 54 | 55 | 56 | public updateVs(key: string, value: any): Thenable 57 | { 58 | return this.configurationWs.update(key, value, ConfigurationTarget.Global); 59 | } 60 | 61 | 62 | public updateVsWs(key: string, value: any): Thenable 63 | { 64 | return this.configurationWs.update(key, value, ConfigurationTarget.Workspace); 65 | } 66 | 67 | 68 | public update(key: string, value: any): Thenable 69 | { 70 | return this.configuration.update(key, value, ConfigurationTarget.Global); 71 | } 72 | 73 | 74 | public updateWs(key: string, value: any): Thenable 75 | { 76 | return this.configuration.update(key, value, ConfigurationTarget.Workspace); 77 | } 78 | 79 | 80 | // public updateWsf(section: string, value: any, uri?: Uri): Thenable 81 | // { 82 | // uri = uri || (workspace.workspaceFolders ? workspace.workspaceFolders[0].uri : undefined); 83 | // return workspace.getConfiguration(extensionName, uri).update(section, value, ConfigurationTarget.WorkspaceFolder); 84 | // } 85 | 86 | 87 | // public inspect(section: string) 88 | // { 89 | // return this.configuration.inspect(section); 90 | // } 91 | 92 | } 93 | 94 | export const configuration = new Configuration(); -------------------------------------------------------------------------------- /src/common/escape.ts: -------------------------------------------------------------------------------- 1 | //https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#8-colors 2 | 3 | export enum TE_Style { 4 | Black = '\u001b[30m', 5 | Red = '\u001b[31m', 6 | Green = '\u001b[32m', 7 | Yellow = '\u001b[33m', 8 | Blue = '\u001b[34m', 9 | Magenta = '\u001b[35m', 10 | Cyan = '\u001b[36m', 11 | White = '\u001b[37m', 12 | 13 | BrightBlack = '\u001b[30;1m', 14 | BrightRed = '\u001b[31;1m', 15 | BrightGreen = '\u001b[32;1m', 16 | BrightYellow = '\u001b[33;1m', 17 | BrightBlue = '\u001b[34;1m', 18 | BrightMagenta = '\u001b[35;1m', 19 | BrightCyan = '\u001b[36;1m', 20 | BrightWhite = '\u001b[37;1m', 21 | 22 | BackgroundBlack = '\u001b[40m', 23 | BackgroundRed = '\u001b[41m', 24 | BackgroundGreen = '\u001b[42m', 25 | BackgroundYellow = '\u001b[43m', 26 | BackgroundBlue = '\u001b[44m', 27 | BackgroundMagenta = '\u001b[45m', 28 | BackgroundCyan = '\u001b[46m', 29 | BackgroundWhite = '\u001b[47m', 30 | 31 | 32 | BackgroundBrightBlack = '\u001b[40;1m', 33 | BackgroundBrightRed = '\u001b[41;1m', 34 | BackgroundBrightGreen = '\u001b[42;1m', 35 | BackgroundBrightYellow = '\u001b[43;1m', 36 | BackgroundBrightBlue = '\u001b[44;1m', 37 | BackgroundBrightMagenta = '\u001b[45;1m', 38 | BackgroundBrightCyan = '\u001b[46;1m', 39 | BackgroundBrightWhite = '\u001b[47;1m', 40 | 41 | Bold = '\u001b[1m', 42 | Underline = '\u001b[4m', 43 | Reversed = '\u001b[7m', 44 | 45 | Reset = '\u001b[0m' 46 | } 47 | export class TerminalEscape { 48 | 49 | constructor() { 50 | 51 | } 52 | static apply({ msg, style }: { msg: string; style: TE_Style[]; }) { 53 | return style.join('') + msg + TE_Style.Reset; 54 | } 55 | } -------------------------------------------------------------------------------- /src/common/util.ts: -------------------------------------------------------------------------------- 1 | import path = require("path"); 2 | import * as vscode from 'vscode'; 3 | /** 4 | * @File : util.ts 5 | * @Author : (coolchyni) 6 | * @Link : 7 | * @Date : 2/13/2022, 11:32:21 AM 8 | * some function copy form https://github.com/microsoft/vscode-cpptools/blob/main/Extension/src/common.ts 9 | */ 10 | 11 | export let extensionPath: string; 12 | export let extensionContext: vscode.ExtensionContext | undefined; 13 | export function setExtensionContext(context: vscode.ExtensionContext): void { 14 | extensionContext = context; 15 | extensionPath = extensionContext.extensionPath; 16 | } 17 | export function setExtensionPath(path: string): void { 18 | extensionPath = path; 19 | } 20 | 21 | export function getExtensionFilePath(extensionfile: string): string { 22 | return path.resolve(extensionPath, extensionfile); 23 | } 24 | export function isVsCodeInsiders(): boolean { 25 | return extensionPath.includes(".vscode-insiders") || 26 | extensionPath.includes(".vscode-server-insiders") || 27 | extensionPath.includes(".vscode-exploration") || 28 | extensionPath.includes(".vscode-server-exploration"); 29 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import * as vscode from 'vscode'; 4 | import { FpcItem, FpcProjectProvider } from './providers/project'; 5 | import { diagCollection, FpcTaskProvider,taskProvider } from './providers/task'; 6 | import { FpcCommandManager } from './commands'; 7 | import * as util from './common/util'; 8 | import {TLangClient} from './languageServer/client'; 9 | import { configuration } from './common/configuration'; 10 | import { JediFormatter } from './formatter'; 11 | import { format } from 'path'; 12 | import * as MyCodeAction from './languageServer/codeaction'; 13 | export let client:TLangClient; 14 | export let formatter:JediFormatter; 15 | export let logger:vscode.OutputChannel; 16 | 17 | // this method is called when your extension is activated 18 | // your extension is activated the very first time the command is executed 19 | export async function activate(context: vscode.ExtensionContext) { 20 | 21 | if (!vscode.workspace.workspaceFolders) { 22 | return; 23 | } 24 | 25 | logger=vscode.window.createOutputChannel('fpctoolkit'); 26 | 27 | vscode.window.onDidChangeVisibleTextEditors(onDidChangeVisibleTextEditors); 28 | vscode.workspace.onDidChangeTextDocument(onDidChangeTextDocument); 29 | util.setExtensionContext(context); 30 | const workspaceRoot = vscode.workspace.workspaceFolders[0].uri.fsPath; 31 | 32 | 33 | let commands = new FpcCommandManager(workspaceRoot); 34 | commands.registerAll(context); 35 | 36 | formatter=new JediFormatter(); 37 | formatter.doInit(); 38 | 39 | let ProjectProvider= new FpcProjectProvider(workspaceRoot,context); 40 | vscode.window.registerTreeDataProvider("FpcProjectExplorer", ProjectProvider); 41 | 42 | //taskProvider=new FpcTaskProvider(workspaceRoot); 43 | context.subscriptions.push(vscode.tasks.registerTaskProvider( 44 | FpcTaskProvider.FpcTaskType, 45 | taskProvider 46 | ) 47 | ); 48 | 49 | 50 | 51 | MyCodeAction.activate(context); 52 | 53 | client=new TLangClient(ProjectProvider); 54 | await client.doInit(); 55 | client.start(); 56 | 57 | 58 | } 59 | 60 | function onDidChangeTextDocument(e:vscode.TextDocumentChangeEvent){ 61 | if(e.contentChanges.length>0){ 62 | if(!diagCollection.has(e.document.uri)){ return ;} 63 | 64 | 65 | for (const change of e.contentChanges) { 66 | let newline=(change.text.match(/\n/g) || '').length+1; 67 | if(change.range.isSingleLine && (newline<2)){ 68 | continue; 69 | } 70 | let diags= diagCollection.get(e.document.uri); 71 | if(!diags){return;} 72 | 73 | let oldline=change.range.end.line-change.range.start.line+1; 74 | 75 | let lines_change=newline-oldline; 76 | let newdiags=[]; 77 | for (const diag of diags) { 78 | if(change.range.contains(diag.range)){//remove it if contains 79 | continue; 80 | } 81 | 82 | if(diag.range.start.line>=change.range.start.line){ 83 | diag.range=new vscode.Range(diag.range.start.line+lines_change,diag.range.start.character,diag.range.end.line+lines_change,diag.range.end.character) 84 | } 85 | newdiags.push(diag) 86 | } 87 | diagCollection.set(e.document.uri, newdiags); 88 | } 89 | 90 | 91 | 92 | } 93 | 94 | } 95 | function onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]): void { 96 | // Process delayed didOpen for any visible editors we haven't seen before 97 | editors.forEach(editor => { 98 | if ((editor.document.uri.scheme === "file") && (editor.document.languageId === "objectpascal" || editor.document.languageId === "pascal" )) { 99 | editor.options.tabSize=configuration.get('format.tabsize',2); 100 | client.onDidChangeVisibleTextEditor(editor); 101 | } 102 | }); 103 | } 104 | // this method is called when your extension is deactivated 105 | export function deactivate() { 106 | if (!client) { 107 | return undefined; 108 | } 109 | return client.stop(); 110 | } 111 | -------------------------------------------------------------------------------- /src/formatter.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as ChildProcess from "child_process"; 3 | import * as util from './common/util'; 4 | import path = require('path'); 5 | import { configuration } from './common/configuration'; 6 | import { env } from 'process'; 7 | import * as fs from 'fs'; 8 | import { client, logger } from './extension'; 9 | import { Console } from 'console'; 10 | 11 | export class JediFormatter { 12 | private jcfpath:string; 13 | private default_cfg:string; 14 | private is_win:boolean=true; 15 | constructor() { 16 | const plat: NodeJS.Platform = process.platform; 17 | const arch = process.arch; 18 | let extensionProcessName = ''; 19 | 20 | if (arch === 'x64') { 21 | if (plat === 'win32') { 22 | extensionProcessName = 'win32/jcf.exe'; 23 | } else if (plat === 'linux') { 24 | extensionProcessName = 'x86_64-linux/jcf'; 25 | } else if (plat == 'darwin') { 26 | extensionProcessName = 'x86_64-darwin/jcf'; 27 | } 28 | else { 29 | throw "Invalid Platform"; 30 | } 31 | } else if (arch === 'arm64') { 32 | if (plat === 'linux') { 33 | extensionProcessName = 'aarch64-linux/jcf'; 34 | } else if (plat == 'darwin') { 35 | extensionProcessName = 'x86_64-darwin/jcf'; 36 | } 37 | else if (plat == 'win32') { 38 | extensionProcessName = 'win32/jcf.exe'; 39 | } else { 40 | throw "Invalid Platform"; 41 | } 42 | } else { 43 | throw "Invalid arch"; 44 | } 45 | this.is_win=plat==='win32'; 46 | 47 | this.jcfpath = path.resolve(util.getExtensionFilePath("bin"), extensionProcessName); 48 | if(!this.is_win){ 49 | fs.chmodSync(this.jcfpath,755); 50 | } 51 | this.default_cfg=path.resolve(util.getExtensionFilePath("bin"),'jcfsettings.cfg'); 52 | let cfg_path=''; 53 | if(this.is_win){ 54 | cfg_path=env.LOCALAPPDATA+'/lazarus/jcfsettings.cfg'; 55 | }else{ 56 | cfg_path=env.HOME+'/.lazarus/jcfsettings.cfg'; 57 | }; 58 | if(fs.existsSync(cfg_path)){ 59 | this.default_cfg=cfg_path; 60 | } 61 | 62 | 63 | } 64 | getCfgConfig():string{ 65 | let cfg=configuration.get("format.cfgpath",""); 66 | if(cfg==""){ 67 | cfg=this.default_cfg; 68 | } 69 | return cfg; 70 | } 71 | doInit() { 72 | let _this = this; 73 | let enable=configuration.get('format.enabled',true); 74 | if(!enable) return; 75 | // 👍 formatter implemented using API 76 | vscode.languages.registerDocumentFormattingEditProvider('objectpascal', { 77 | provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.ProviderResult { 78 | let cfg_path=_this.getCfgConfig(); 79 | let proc= ChildProcess.spawn(_this.jcfpath, ['-inplace', '-y','-config='+cfg_path,'-F' ,document.fileName] ); 80 | logger.appendLine(proc.spawnargs.join(' ')); 81 | proc.stdout.on('data', (data) => { 82 | logger.appendLine(data); 83 | console.log(`stdout: ${data}`); 84 | }); 85 | 86 | proc.stderr.on('data', (data) => { 87 | logger.appendLine(data); 88 | console.error(`stderr: ${data}`); 89 | }); 90 | 91 | proc.on('close', (code) => { 92 | console.log(`child process exited with code ${code}`); 93 | }); 94 | proc.unref(); 95 | return []; 96 | } 97 | }); 98 | 99 | } 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/languageServer/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @File : client.ts 3 | * @Author : (coolchyni) 4 | * @Link : 5 | * @Date : 2/16/2022, 11:26:06 PM 6 | */ 7 | import path = require('path'); 8 | import * as vscode from 'vscode'; 9 | import { workspace } from 'vscode'; 10 | import { 11 | State, 12 | NotificationType, 13 | LanguageClient, 14 | ServerOptions, 15 | Executable, 16 | LanguageClientOptions, 17 | ShowMessageNotification, 18 | ShowMessageParams, 19 | MessageType, 20 | ExecuteCommandRequest, 21 | ExecuteCommandParams, 22 | ErrorHandler, 23 | Message, 24 | ErrorHandlerResult, 25 | ErrorAction, 26 | CloseHandlerResult, 27 | CloseAction} from 'vscode-languageclient/node'; 28 | 29 | import { FpcProjectProvider } from '../providers/project'; 30 | import * as util from '../common/util'; 31 | import { CompileOption, InitializationOptions } from "./options"; 32 | import { env } from 'process'; 33 | import * as fs from 'fs-extra'; 34 | import { client, logger } from '../extension'; 35 | import { ClientRequest } from 'http'; 36 | 37 | interface InputRegion { 38 | startLine: number; 39 | startCol:number; 40 | endLine: number; 41 | endCol:number; 42 | } 43 | 44 | interface DecorationRangesPair { 45 | decoration: vscode.TextEditorDecorationType; 46 | ranges: vscode.Range[]; 47 | } 48 | 49 | interface InactiveRegionParams { 50 | uri: string; 51 | fileVersion: number; 52 | regions: InputRegion[]; 53 | } 54 | 55 | // Notifications from the server 56 | const InactiveRegionNotification: NotificationType = new NotificationType('pasls/inactiveRegions'); 57 | 58 | //set cursor pos 59 | interface SetSelectionParams { 60 | uri: string; 61 | /** 62 | * The position at which the selection starts. 63 | * This position might be before or after {@link Selection.active active}. 64 | */ 65 | anchor: vscode.Position; 66 | 67 | /** 68 | * The position of the cursor. 69 | * This position might be before or after {@link Selection.anchor anchor}. 70 | */ 71 | active: vscode.Position; 72 | } 73 | const SetSelectionNotification: NotificationType = new NotificationType('pasls/setSelection'); 74 | 75 | function GetEnvironmentVariables(): {} { 76 | // load environment variables from settings which are used for CodeTools 77 | const plat = process.platform; 78 | let userEnvironmentVariables = {}; 79 | let keys: string[] = ['PP', 'FPCDIR', 'LAZARUSDIR', 'FPCTARGET', 'FPCTARGETCPU']; 80 | let settingEnvironmentVariables = workspace.getConfiguration('fpctoolkit.env'); 81 | Object.keys(settingEnvironmentVariables).forEach(key => { 82 | if (keys.includes(key)) { 83 | if (settingEnvironmentVariables[key]) { 84 | userEnvironmentVariables[key] = settingEnvironmentVariables[key]; 85 | } 86 | } 87 | }); 88 | //set default value 89 | let PP = settingEnvironmentVariables.get('PP'); 90 | if (PP === undefined || PP === '') //not init 91 | { 92 | if (plat === 'win32') { 93 | ///3.2.2/bin/i386-win32/fpc.exe 94 | //search lazarus 95 | let dirs = ['C:/lazarus/fpc', 'C:/FPC']; 96 | let ver_test = /\d+\.\d+\.\d+/; 97 | for (const _dir of dirs) { 98 | if (fs.pathExistsSync(_dir)) { 99 | let subdirs = fs.readdirSync(_dir); 100 | for (const fpcver of subdirs) { 101 | if (ver_test.test(fpcver)) { //found it 102 | if (_dir.startsWith('C:/lazarus')) { 103 | userEnvironmentVariables['LAZARUSDIR'] = 'C:/lazarus'; 104 | env['LAZARUSDIR'] = userEnvironmentVariables['LAZARUSDIR']; 105 | } 106 | userEnvironmentVariables['PP'] = path.join(_dir, fpcver, 'bin', 'i386-win32', 'fpc.exe'); 107 | userEnvironmentVariables['FPCDIR'] = path.join(_dir, fpcver, 'source'); 108 | env['PP'] = userEnvironmentVariables['PP']; 109 | 110 | return userEnvironmentVariables; 111 | } 112 | } 113 | } 114 | } 115 | } else { 116 | let dirs = ['/usr/bin/fpc', '/usr/local/bin/fpc']; 117 | let ver_test = new RegExp('\d+\.\d+\.\d+'); 118 | for (const _dir of dirs) { 119 | if (fs.existsSync(_dir)) { 120 | userEnvironmentVariables['PP'] = _dir; 121 | } 122 | } 123 | if (fs.existsSync('/usr/local/share/fpcsrc')) { 124 | userEnvironmentVariables['FPCDIR'] = '/usr/local/share/fpcsrc'; 125 | } 126 | } 127 | } 128 | 129 | env['PP'] = userEnvironmentVariables['PP']; 130 | env['LAZARUSDIR'] = userEnvironmentVariables['LAZARUSDIR']; 131 | 132 | return userEnvironmentVariables; 133 | } 134 | interface myConfiguration extends vscode.WorkspaceConfiguration { 135 | cwd: string; 136 | } 137 | export class TLangClient implements ErrorHandler { 138 | private client: LanguageClient | undefined; 139 | private targetOS?: string; 140 | private targetCPU?: string; 141 | private inactiveRegionsDecorations = new Map(); 142 | constructor( 143 | public projProvider: FpcProjectProvider 144 | ) { 145 | this.client = undefined; 146 | }; 147 | 148 | /** 149 | * An error has occurred while writing or reading from the connection. 150 | * 151 | * @param error - the error received 152 | * @param message - the message to be delivered to the server if know. 153 | * @param count - a count indicating how often an error is received. Will 154 | * be reset if a message got successfully send or received. 155 | */ 156 | error(error: Error, message: Message | undefined, count: number | undefined): ErrorHandlerResult{ 157 | logger.appendLine(error.name+' '+error.message); 158 | return {action:ErrorAction.Continue} as ErrorHandlerResult; 159 | } 160 | /** 161 | * The connection to the server got closed. 162 | */ 163 | closed(): CloseHandlerResult{ 164 | logger.appendLine("Server closed."); 165 | return {action:CloseAction.Restart} as CloseHandlerResult; 166 | } 167 | 168 | private getLanguageServerFileName(): string { 169 | let extensionProcessName: string = 'pasls'; 170 | let paslspath=vscode.workspace.getConfiguration('fpctoolkit.pasls').get('path'); 171 | 172 | 173 | const plat: NodeJS.Platform = process.platform; 174 | const arch = process.arch; 175 | if (arch === 'x64') { 176 | this.targetCPU = 'x86_64'; 177 | if (plat === 'win32') { 178 | extensionProcessName = 'win32/pasls.exe'; 179 | this.targetOS = 'win64'; 180 | } else if (plat === 'linux') { 181 | extensionProcessName = 'x86_64-linux/pasls'; 182 | this.targetOS = 'linux'; 183 | } else if (plat == 'darwin') { 184 | extensionProcessName = 'x86_64-darwin/pasls'; 185 | this.targetOS = 'darwin'; 186 | } 187 | else { 188 | throw "Invalid Platform"; 189 | } 190 | } else if (arch === 'arm64') { 191 | this.targetCPU = 'aarch64'; 192 | if (plat === 'linux') { 193 | extensionProcessName = 'aarch64-linux/pasls'; 194 | this.targetOS = 'linux'; 195 | } else if (plat == 'darwin') { 196 | extensionProcessName = 'x86_64-darwin/pasls'; 197 | this.targetOS = 'darwin'; 198 | } 199 | else if (plat == 'win32') { 200 | this.targetOS = 'win32'; 201 | extensionProcessName = 'win32/pasls.exe'; 202 | } else { 203 | throw "Invalid Platform"; 204 | } 205 | } else { 206 | throw "Invalid arch"; 207 | } 208 | if(paslspath && paslspath.length>0){ 209 | return paslspath; 210 | } 211 | return path.resolve(util.getExtensionFilePath("bin"), extensionProcessName); 212 | }; 213 | async doOnReady() { 214 | this.client?.onNotification(ShowMessageNotification.type, (e: ShowMessageParams) => { 215 | //vscode.window.showErrorMessage(e.message); 216 | 217 | switch (e.type) { 218 | case MessageType.Info: 219 | vscode.window.showInformationMessage(e.message); 220 | break; 221 | case MessageType.Warning: 222 | vscode.window.showWarningMessage(e.message); 223 | break; 224 | case MessageType.Error: 225 | if ((e as any).hasFile) { 226 | let f = e.message.split('@') 227 | let file = f[0].split(' ')[0]; 228 | let pos = f[1].split(':'); 229 | 230 | let position: vscode.Position = new vscode.Position(Number.parseInt(pos[0]), Number.parseInt(pos[1])); 231 | 232 | let diag=new vscode.Diagnostic(new vscode.Range(position,position),e.message); 233 | 234 | this.client?.diagnostics?.set( vscode.Uri.parse(file),[diag]); 235 | 236 | 237 | vscode.window.showErrorMessage(e.message, 'View Error').then(item => { 238 | if (item === 'View Error') { 239 | vscode.workspace.openTextDocument(file).then(doc => { 240 | 241 | let position: vscode.Position = new vscode.Position(Number.parseInt(pos[0]), Number.parseInt(pos[1])); 242 | vscode.window.showTextDocument(doc, { selection: new vscode.Selection(position, position) }); 243 | }); 244 | 245 | } 246 | 247 | }); 248 | 249 | } else { 250 | vscode.window.showErrorMessage(e.message); 251 | } 252 | 253 | 254 | break; 255 | 256 | default: 257 | break; 258 | } 259 | 260 | 261 | }); 262 | this.client?.onNotification(InactiveRegionNotification, (params: InactiveRegionParams) => { 263 | //const settings: CppSettings = new CppSettings(this.RootUri); 264 | const opacity: number | undefined = 0.3;//settings.inactiveRegionOpacity; 265 | if (opacity !== null && opacity !== undefined) { 266 | let backgroundColor: string | undefined = "";//settings.inactiveRegionBackgroundColor; 267 | if (backgroundColor === "") { 268 | backgroundColor = undefined; 269 | } 270 | let color: string | undefined = "";//settings.inactiveRegionForegroundColor; 271 | if (color === "") { 272 | color = undefined; 273 | } 274 | const decoration: vscode.TextEditorDecorationType = vscode.window.createTextEditorDecorationType({ 275 | opacity: opacity.toString(), 276 | backgroundColor: backgroundColor, 277 | color: color, 278 | rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen 279 | }); 280 | // We must convert to vscode.Ranges in order to make use of the API's 281 | const ranges: vscode.Range[] = []; 282 | params.regions.forEach(element => { 283 | const newRange: vscode.Range = new vscode.Range(element.startLine-1, element.startCol-1, element.endLine-1, element.endCol-1); 284 | ranges.push(newRange); 285 | }); 286 | // Find entry for cached file and act accordingly 287 | const valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(params.uri); 288 | if (valuePair) { 289 | // Disposing of and resetting the decoration will undo previously applied text decorations 290 | valuePair.decoration.dispose(); 291 | valuePair.decoration = decoration; 292 | // As vscode.TextEditor.setDecorations only applies to visible editors, we must cache the range for when another editor becomes visible 293 | valuePair.ranges = ranges; 294 | } else { // The entry does not exist. Make a new one 295 | const toInsert: DecorationRangesPair = { 296 | decoration: decoration, 297 | ranges: ranges 298 | }; 299 | this.inactiveRegionsDecorations.set(params.uri, toInsert); 300 | } 301 | //if (settings.dimInactiveRegions && params.fileVersion === openFileVersions.get(params.uri)) { 302 | // Apply the decorations to all *visible* text editors 303 | const editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === params.uri); 304 | for (const e of editors) { 305 | e.setDecorations(decoration, ranges); 306 | } 307 | //} 308 | } 309 | 310 | }); 311 | 312 | this.client?.onNotification(SetSelectionNotification, (params: SetSelectionParams) => { 313 | let uri=vscode.Uri.parse(params.uri); 314 | vscode.workspace.openTextDocument(uri).then(doc => { 315 | setTimeout(() => { 316 | vscode.window.showTextDocument(doc, { selection: new vscode.Selection(params.anchor, params.active) }); 317 | }, 500); 318 | }); 319 | }); 320 | 321 | } 322 | async doInit() { 323 | //lsp 324 | 325 | console.log("Greetings from pascal-language-server 🙏"); 326 | 327 | // Load the path to the language server from settings 328 | //let executable: string = workspace.getConfiguration('pascalLanguageServer').get("executable")!; 329 | let executable: string = this.getLanguageServerFileName(); 330 | if(process.platform!='win32'){ 331 | fs.chmod(executable,755); 332 | } 333 | // TODO: download the executable for the active platform 334 | // https://github.com/genericptr/pascal-language-server/releases/download/x86_64-darwin/pasls 335 | // if (!executable) { 336 | // let target = 'x86_64-darwin'; 337 | // executable = context.asAbsolutePath(path.join('bin', target, 'pasls')); 338 | // } 339 | 340 | console.log("executable: " + executable); 341 | 342 | let run: Executable = { 343 | command: executable, 344 | options: { 345 | env: GetEnvironmentVariables() 346 | } 347 | }; 348 | let debug: Executable = run; 349 | 350 | let serverOptions: ServerOptions = { 351 | run, 352 | debug 353 | }; 354 | 355 | //Connect to language server via socket 356 | 357 | //rpcjson 358 | // The server is a started as a separate app and listens on port 5007 359 | // let connectionInfo = { 360 | // port: 9999 361 | // }; 362 | // let serverOptions = () => { 363 | 364 | // let socket = net.connect(connectionInfo); 365 | // socket.on("data",(data:Buffer)=>{ 366 | // console.info(data.toString()); 367 | // }); 368 | 369 | // let result: StreamInfo = { 370 | // writer: socket, 371 | // reader: socket 372 | // }; 373 | // return Promise.resolve(result); 374 | // }; 375 | 376 | var initializationOptions = new InitializationOptions(); 377 | 378 | let opt = await this.projProvider.GetDefaultTaskOption(); 379 | if (opt != undefined) { 380 | initializationOptions.updateByCompileOption(opt); 381 | } else { 382 | opt = new CompileOption(); 383 | opt.buildOption!.targetCPU = this.targetCPU; 384 | opt.buildOption!.targetOS = this.targetOS; 385 | } 386 | 387 | // client extensions configure their server 388 | let clientOptions: LanguageClientOptions = { 389 | initializationOptions: initializationOptions, 390 | errorHandler: this, 391 | // workspaceFolder: folder, 392 | documentSelector: [ 393 | { scheme: 'file', language: 'objectpascal' }, 394 | { scheme: 'untitled', language: 'objectpascal' } 395 | ] 396 | } 397 | 398 | this.client = new LanguageClient('fpctoolkit.lsp', 'Free Pascal Language Server', serverOptions, clientOptions); 399 | 400 | }; 401 | public onDidChangeVisibleTextEditor(editor: vscode.TextEditor): void { 402 | 403 | // Apply text decorations to inactive regions 404 | const valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(editor.document.uri.toString()); 405 | if (valuePair) { 406 | editor.setDecorations(valuePair.decoration, valuePair.ranges); // VSCode clears the decorations when the text editor becomes invisible 407 | } 408 | 409 | } 410 | 411 | async start(): Promise { 412 | await this.client?.start(); 413 | await this.doOnReady(); 414 | }; 415 | async stop(): Promise { 416 | this.client?.stop(); 417 | }; 418 | 419 | async restart(): Promise { 420 | 421 | await this.client?.stop(); 422 | await this.doInit(); 423 | await this.client?.start(); 424 | await this.doOnReady(); 425 | 426 | }; 427 | 428 | async doCodeComplete(editor:vscode.TextEditor): Promise { 429 | let sel=editor.selection.start; 430 | var req:ExecuteCommandParams={ 431 | command:"CompleteCode", 432 | arguments:[ 433 | editor.document.uri.toString(), 434 | sel.line.toString(), 435 | sel.character.toString() 436 | ] 437 | }; 438 | let result:ExecuteCommandParams=await this.client?.sendRequest(ExecuteCommandRequest.type,req); 439 | 440 | if(result.arguments![0]=='true'){ 441 | 442 | let newLine=Number.parseInt( result.arguments![3] ); 443 | let newCharacter=Number.parseInt(result.arguments![2]); 444 | // let newTopLine=Number.parseInt(result.arguments![3]); 445 | 446 | let blocktop=Number.parseInt(result.arguments![4]); 447 | if(blocktop==0) 448 | { 449 | return ; 450 | } 451 | // let blockContent=result.arguments![5]; 452 | 453 | let pos=new vscode.Position(newLine,newCharacter); 454 | setTimeout(() => { 455 | vscode.window.showTextDocument(editor.document, { selection: new vscode.Selection(pos,pos) }); 456 | }, 200); 457 | 458 | } 459 | 460 | 461 | } 462 | 463 | async getUnitPath( unitnames:string[]): Promise { 464 | 465 | var req:ExecuteCommandParams={ 466 | command:"GetUnitPath", 467 | arguments:unitnames 468 | }; 469 | let result:ExecuteCommandParams=await this.client?.sendRequest(ExecuteCommandRequest.type,req); 470 | 471 | 472 | if(result.arguments){ 473 | return result.arguments; 474 | }else{ 475 | return []; 476 | } 477 | 478 | } 479 | } -------------------------------------------------------------------------------- /src/languageServer/codeaction.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | // sample 5 | // https://github.com/microsoft/vscode-extension-samples/blob/main/code-actions-sample/src/extension.ts 6 | 7 | import { match } from 'assert'; 8 | import { disconnect } from 'process'; 9 | import * as vscode from 'vscode'; 10 | import { diagCollection } from '../providers/task'; 11 | 12 | const COMMAND_UNUSED = 'fpctoolkit.code-actions.remove_unused_variable'; 13 | 14 | export function activate(context: vscode.ExtensionContext) { 15 | // context.subscriptions.push( 16 | // vscode.languages.registerCodeActionsProvider('objectpascal', new Emojizer(), { 17 | // providedCodeActionKinds: Emojizer.providedCodeActionKinds 18 | // })); 19 | 20 | // const emojiDiagnostics = vscode.languages.createDiagnosticCollection("emoji"); 21 | // context.subscriptions.push(emojiDiagnostics); 22 | 23 | 24 | 25 | context.subscriptions.push( 26 | vscode.languages.registerCodeActionsProvider('objectpascal', new FpcCodeAction(), { 27 | providedCodeActionKinds: FpcCodeAction.providedCodeActionKinds 28 | }) 29 | ); 30 | 31 | context.subscriptions.push( 32 | vscode.commands.registerCommand(COMMAND_UNUSED, (document:vscode.TextDocument,diag:vscode.Diagnostic,variable:string) => { 33 | let edit=new vscode.WorkspaceEdit(); 34 | let line=document.lineAt(diag.range.start.line); 35 | let linetext=line.text.trim(); 36 | var has_var=false; 37 | if(linetext.substring(0,4).toLocaleLowerCase()=='var ') 38 | { 39 | linetext=linetext.substring(4,linetext.length) 40 | has_var=true; 41 | } 42 | let isdelete=false; 43 | let ret=linetext.split(/,|:/); 44 | if(ret.length<=2){ 45 | if(has_var){ 46 | edit.replace(document.uri,line.range,"var"); 47 | }else{ 48 | edit.delete(document.uri,line.rangeIncludingLineBreak); 49 | isdelete=true; 50 | } 51 | }else{ 52 | ret=ret.map(v=>v.trim()).filter(v=>v!=variable); 53 | linetext=has_var?'var ':' '+ret.slice(0,-1).join(', ')+': '+ret[ret.length-1]; 54 | edit.replace(document.uri,line.range,linetext); 55 | } 56 | 57 | let diags= diagCollection.get(document.uri); 58 | if(!diags){ 59 | vscode.workspace.applyEdit(edit); 60 | return; 61 | } 62 | if(!isdelete){ 63 | //delete fixed diag 64 | 65 | var newdiags=[]; 66 | for (const item of diags) { 67 | if(item===diag) 68 | { 69 | continue; 70 | } 71 | 72 | //chagne diag pos use workspace.onDidChangeTextDocument 73 | // if(isdelete && item.range.start.line>=line.range.start.line){ 74 | // item.range=new vscode.Range(item.range.start.line-1,item.range.start.character,item.range.end.line-1,item.range.end.character) 75 | // } 76 | newdiags.push(item) 77 | } 78 | diagCollection.set(document.uri, newdiags); 79 | } 80 | 81 | 82 | vscode.workspace.applyEdit(edit); 83 | 84 | }) 85 | ); 86 | } 87 | 88 | /** 89 | * Provides code actions for converting :) to a smiley emoji. 90 | */ 91 | // export class Emojizer implements vscode.CodeActionProvider { 92 | 93 | // public static readonly providedCodeActionKinds = [ 94 | // vscode.CodeActionKind.QuickFix 95 | // ]; 96 | 97 | // public provideCodeActions(document: vscode.TextDocument, range: vscode.Range): vscode.CodeAction[] | undefined { 98 | // if (!this.isAtStartOfSmiley(document, range)) { 99 | // return; 100 | // } 101 | 102 | // const replaceWithSmileyCatFix = this.createFix(document, range, '😺'); 103 | 104 | // const replaceWithSmileyFix = this.createFix(document, range, '😀'); 105 | // // Marking a single fix as `preferred` means that users can apply it with a 106 | // // single keyboard shortcut using the `Auto Fix` command. 107 | // replaceWithSmileyFix.isPreferred = true; 108 | 109 | // const replaceWithSmileyHankyFix = this.createFix(document, range, '💩'); 110 | 111 | // const commandAction = this.createCommand(); 112 | 113 | // return [ 114 | // replaceWithSmileyCatFix, 115 | // replaceWithSmileyFix, 116 | // replaceWithSmileyHankyFix, 117 | // commandAction 118 | // ]; 119 | // } 120 | 121 | // private isAtStartOfSmiley(document: vscode.TextDocument, range: vscode.Range) { 122 | // const start = range.start; 123 | // const line = document.lineAt(start.line); 124 | // return line.text[start.character] === ':' && line.text[start.character + 1] === ')'; 125 | // } 126 | 127 | // private createFix(document: vscode.TextDocument, range: vscode.Range, emoji: string): vscode.CodeAction { 128 | // const fix = new vscode.CodeAction(`Convert to ${emoji}`, vscode.CodeActionKind.QuickFix); 129 | // fix.edit = new vscode.WorkspaceEdit(); 130 | // fix.edit.replace(document.uri, new vscode.Range(range.start, range.start.translate(0, 2)), emoji); 131 | // return fix; 132 | // } 133 | 134 | // private createCommand(): vscode.CodeAction { 135 | // const action = new vscode.CodeAction('Learn more...', vscode.CodeActionKind.Empty); 136 | // action.command = { command: COMMAND, title: 'Learn more about emojis', tooltip: 'This will open the unicode emoji page.' }; 137 | // return action; 138 | // } 139 | // } 140 | 141 | /** 142 | * Provides code actions corresponding to diagnostic problems. 143 | */ 144 | export class FpcCodeAction implements vscode.CodeActionProvider { 145 | 146 | public static readonly providedCodeActionKinds = [ 147 | vscode.CodeActionKind.QuickFix 148 | ]; 149 | 150 | provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): vscode.CodeAction[] { 151 | // for each diagnostic entry that has the matching `code`, create a code action command 152 | return context.diagnostics 153 | .filter(diagnostic =>{ 154 | return diagnostic.code === 5025; 155 | } ) 156 | .map(diagnostic => this.createCommandCodeAction(document,diagnostic)); 157 | } 158 | 159 | private createCommandCodeAction(document: vscode.TextDocument,diagnostic: vscode.Diagnostic): vscode.CodeAction { 160 | let matchs=diagnostic.message.match(/Local variable "(.*?)".*?not used/)!; 161 | 162 | let variable=matchs[1]; 163 | 164 | const fix = new vscode.CodeAction('Remove variable `'+variable+'`', vscode.CodeActionKind.QuickFix); 165 | fix.command = { command: COMMAND_UNUSED, title: 'Remove unused variable.', tooltip: 'Remove unused variable.' }; 166 | fix.command.arguments=[document, diagnostic,variable]; 167 | fix.diagnostics = [diagnostic]; 168 | //fix.isPreferred = true; 169 | return fix; 170 | } 171 | } -------------------------------------------------------------------------------- /src/languageServer/options.ts: -------------------------------------------------------------------------------- 1 | import internal = require('stream'); 2 | import * as vscode from 'vscode'; 3 | import * as fs from 'fs'; 4 | import * as path from 'path'; 5 | import { configuration } from '../common/configuration'; 6 | import { BuildOption, FpcTaskDefinition } from '../providers/task'; 7 | export class CompileOption { 8 | /** 9 | * Compile Option 10 | */ 11 | public type: string = "fpc"; 12 | public cwd: string = ""; 13 | public label: string = ''; 14 | public file: string = ''; 15 | public windows?: { customOptions?: string[] }; 16 | public linux?: { customOptions?: string[] }; 17 | public darwin?: { customOptions?: string[] }; 18 | 19 | public presentation = { 20 | showReuseMessage: false, 21 | clear: true, 22 | revealProblems: "onProblem" 23 | }; 24 | public buildOption?:BuildOption; 25 | 26 | 27 | constructor( 28 | 29 | taskDefinition?: FpcTaskDefinition, 30 | workspaceRoot?:string 31 | 32 | ) { 33 | if (taskDefinition) { 34 | this.file = taskDefinition.file??""; 35 | this.label = taskDefinition.file??"untitled"; 36 | this.windows = taskDefinition.windows; 37 | this.buildOption = taskDefinition.buildOption; 38 | if(workspaceRoot){ 39 | if (taskDefinition.cwd) { 40 | this.cwd = path.join(workspaceRoot, taskDefinition.cwd); 41 | } else { 42 | this.cwd = workspaceRoot; 43 | } 44 | }else{ 45 | this.cwd=taskDefinition.cwd??""; 46 | } 47 | 48 | 49 | } else { 50 | this.buildOption = { 51 | unitOutputDir: "./out", 52 | customOptions: [ 53 | "-dDEBUG" 54 | ] 55 | }; 56 | } 57 | 58 | 59 | } 60 | 61 | toOptionString() { 62 | let fpccfg = configuration; 63 | let globalOption = { 64 | customOptions: fpccfg.get('customOptions'), 65 | libPath: fpccfg.get('libPath'), 66 | searchPath: fpccfg.get('searchPath'), 67 | }; 68 | let plat = process.platform; 69 | var plat_options:string[]|undefined; 70 | if (plat == 'win32') { 71 | plat_options=this.windows?.customOptions; 72 | } else if (plat == 'linux') { 73 | plat_options=this.linux?.customOptions; 74 | } else if (plat == 'darwin') { 75 | plat_options=this.darwin?.customOptions; 76 | } 77 | 78 | let s: string = ''; 79 | plat_options?.forEach((e) => { 80 | s += e + " "; 81 | }); 82 | if (this.buildOption?.targetOS) { 83 | s += "-T" + this.buildOption!.targetOS + " "; 84 | } 85 | if (this.buildOption?.targetCPU) { 86 | s += "-P" + this.buildOption!.targetCPU + " "; 87 | } 88 | if(this.buildOption?.forceRebuild){ 89 | s +='-B ' 90 | } 91 | if(this.buildOption?.msgIgnore && this.buildOption.msgIgnore.length>0){ 92 | s+='-vm'+this.buildOption.msgIgnore.join(',')+' '; 93 | } 94 | if (this.buildOption?.outputFile) { 95 | let outfile = this.buildOption!.outputFile; 96 | if (outfile.startsWith(".")) { 97 | outfile = path.join(vscode.workspace.workspaceFolders![0].uri.fsPath, outfile); 98 | } 99 | let dir = path.dirname(outfile); 100 | if (!fs.existsSync(dir)) { 101 | try { 102 | fs.mkdirSync(dir, { recursive: true }); 103 | } catch (error) { 104 | vscode.window.showErrorMessage("Can't create output directory.(" + dir + ")"); 105 | } 106 | 107 | } 108 | s += "-o" + this.buildOption!.outputFile + " "; 109 | } 110 | 111 | globalOption?.searchPath?.forEach((e) => { 112 | s += "-Fu" + e + " "; 113 | }); 114 | globalOption?.libPath?.forEach((e) => { 115 | s += "-Fl" + e + " "; 116 | }); 117 | 118 | 119 | this.buildOption?.searchPath?.forEach((e) => { 120 | s += "-Fu" + e + " "; 121 | }); 122 | this.buildOption?.libPath?.forEach((e) => { 123 | s += "-Fl" + e + " "; 124 | }); 125 | 126 | if (this.buildOption?.unitOutputDir) { 127 | let dir = this.buildOption!.unitOutputDir; 128 | 129 | if (dir.startsWith(".")) { 130 | dir = path.join(vscode.workspace.workspaceFolders![0].uri.fsPath, dir); 131 | } 132 | 133 | if (!fs.existsSync(dir)) { 134 | try { 135 | fs.mkdirSync(dir, { recursive: true }); 136 | } catch (error) { 137 | vscode.window.showErrorMessage("Can't create unit output directory.(" + dir + ")"); 138 | } 139 | 140 | } 141 | s += "-FU" + this.buildOption!.unitOutputDir + " "; 142 | } 143 | 144 | if (this.buildOption?.optimizationLevel) { 145 | s += "-O" + this.buildOption!.optimizationLevel + " "; 146 | } 147 | 148 | if (this.buildOption?.syntaxMode) { 149 | s += "-M" + this.buildOption!.syntaxMode + " "; 150 | } 151 | globalOption?.customOptions?.forEach((e) => { 152 | s += e + " "; 153 | }); 154 | this.buildOption?.customOptions?.forEach((e) => { 155 | s += e + " "; 156 | }); 157 | 158 | 159 | return s; 160 | } 161 | 162 | } 163 | export class TaskInfo { 164 | ischanged: boolean = false; 165 | tasks: any; 166 | } 167 | 168 | 169 | export class InitializationOptions { 170 | //current work path 171 | public cwd: string | undefined; 172 | // Path to the main program file for resolving references 173 | // if not available the path of the current document will be used 174 | public program: string | undefined; 175 | // Path to SQLite3 database for symbols 176 | public symbolDatabase: string | undefined; 177 | // FPC compiler options (passed to Code Tools) 178 | public fpcOptions: Array = []; 179 | // Maximum number of completion items to be returned 180 | // if the threshold is reached then CompletionList.isIncomplete = true 181 | public maximumCompletions: number = 100; 182 | // Policy which determines how overloaded document symbols are displayed 183 | public overloadPolicy: number | undefined; 184 | // procedure completions with parameters are inserted as snippets 185 | public insertCompletionsAsSnippets: boolean | undefined; 186 | // procedure completions with parameters (non-snippet) insert 187 | // empty brackets (and insert as snippet) 188 | public insertCompletionProcedureBrackets: boolean | undefined; 189 | // workspaces folders will be added to unit paths (i.e. -Fu) 190 | public includeWorkspaceFoldersAsUnitPaths: boolean | undefined; 191 | // workspaces folders will be added to include paths (i.e. -Fi) 192 | public includeWorkspaceFoldersAsIncludePaths: boolean | undefined; 193 | // syntax will be checked when file opens or saves 194 | public checkSyntax: boolean | undefined; 195 | // syntax errors will be published as diagnostics 196 | public publishDiagnostics: boolean | undefined; 197 | // enable workspace symbols 198 | public workspaceSymbols: boolean | undefined; 199 | // enable document symbols 200 | public documentSymbols: boolean | undefined; 201 | // completions contain a minimal amount of extra information 202 | public minimalisticCompletions: boolean | undefined; 203 | // syntax errors as shown in the UI with ‘window/showMessage’ 204 | public showSyntaxErrors: boolean | undefined; 205 | // ignores completion items like "begin" and "var" which may interfer with IDE snippets 206 | public ignoreTextCompletions: boolean | undefined; 207 | 208 | constructor() { 209 | let cfg = vscode.workspace.getConfiguration('fpctoolkit.lsp.initializationOptions'); 210 | this.program = cfg.get('program'); 211 | this.maximumCompletions = cfg.get('maximumCompletions', 100); 212 | this.fpcOptions = cfg.get>("fpcOptions", []); 213 | this.overloadPolicy = cfg.get("overloadPolicy"); 214 | this.insertCompletionsAsSnippets = cfg.get('insertCompletionsAsSnippets'); 215 | this.insertCompletionsAsSnippets = cfg.get('insertCompletionsAsSnippets'); 216 | this.includeWorkspaceFoldersAsIncludePaths = cfg.get('insertCompletionsAsSnippets'); 217 | this.includeWorkspaceFoldersAsUnitPaths = cfg.get('includeWorkspaceFoldersAsUnitPaths'); 218 | this.checkSyntax = cfg.get('checkSyntax'); 219 | this.publishDiagnostics = cfg.get('publishDiagnostics'); 220 | this.workspaceSymbols = cfg.get('workspaceSymbols'); 221 | this.documentSymbols = cfg.get('documentSymbols'); 222 | this.minimalisticCompletions = cfg.get('minimalisticCompletions'); 223 | this.showSyntaxErrors = cfg.get('showSyntaxErrors'); 224 | this.ignoreTextCompletions = cfg.get('ignoreTextCompletions'); 225 | } 226 | public updateByCompileOption(opt: CompileOption) { 227 | this.cwd = opt.cwd; 228 | this.program = opt.file; 229 | let fpcOptions: Array = this.fpcOptions; 230 | let newopt = opt.toOptionString().split(' '); 231 | newopt.forEach((s) => { 232 | //if (s.startsWith('-Fi') || s.startsWith('-Fu') || s.startsWith('-d') || s.startsWith('-M')) { 233 | if (!s.startsWith('-v')) { //-v will raise error ,hide it 234 | fpcOptions.push(s); 235 | } 236 | }); 237 | 238 | } 239 | } -------------------------------------------------------------------------------- /src/providers/project.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as fs from 'fs'; 3 | import * as path from 'path'; 4 | import { basename, normalize } from 'path'; 5 | import { CompileOption, TaskInfo } from '../languageServer/options'; 6 | import { openStdin } from 'process'; 7 | import { FpcTaskDefinition, FpcTaskProvider, taskProvider } from './task'; 8 | import { Command } from 'vscode-languageserver-types'; 9 | //import { visit, JSONVisitor } from "jsonc-parser"; 10 | import { pathExists } from 'fs-extra'; 11 | import { Event } from 'vscode-languageclient'; 12 | import { clearTimeout } from 'timers'; 13 | import { TIMEOUT } from 'dns'; 14 | 15 | export class FpcProjectProvider implements vscode.TreeDataProvider { 16 | 17 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 18 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 19 | private watch!: vscode.FileSystemWatcher; 20 | private watchlpr!: vscode.FileSystemWatcher; 21 | public defaultFtpItem?: FpcItem = undefined; 22 | private config!:vscode.WorkspaceConfiguration; 23 | private defaultCompileOption?:CompileOption=undefined; 24 | private timeout?:NodeJS.Timeout=undefined; 25 | constructor(private workspaceRoot: string, context: vscode.ExtensionContext) { 26 | const subscriptions = context.subscriptions; 27 | const name = 'FpcProjectExplorer'; 28 | subscriptions.push(vscode.commands.registerCommand(name + ".open", async (item: FpcItem) => { await this.open(item); }, this)); 29 | 30 | this.watch = vscode.workspace.createFileSystemWatcher(path.join(workspaceRoot,".vscode","tasks.json"), false); 31 | this.watch.onDidChange(async (url) => { 32 | taskProvider.clean(); 33 | if(this.timeout!=undefined){ 34 | clearTimeout(this.timeout); 35 | } 36 | this.timeout=setTimeout(()=>{ 37 | this.checkDefaultAndRefresh(); 38 | },1000); 39 | }); 40 | this.watch.onDidDelete(() => { 41 | this.refresh(); 42 | }); 43 | 44 | this.watchlpr = vscode.workspace.createFileSystemWatcher("**/*.lpr", false, true, false); 45 | this.watchlpr.onDidCreate(() => { 46 | this.refresh(); 47 | }); 48 | this.watchlpr.onDidDelete(() => { 49 | this.refresh(); 50 | }); 51 | 52 | } 53 | 54 | 55 | dispose() { 56 | throw new Error("Method not implemented."); 57 | } 58 | 59 | 60 | /*TreeDataProvider*/ 61 | refresh(): void { 62 | this._onDidChangeTreeData.fire(); 63 | } 64 | 65 | async checkDefaultAndRefresh():Promise{ 66 | let oldCompileOption=this.defaultCompileOption; 67 | if(oldCompileOption==undefined){ 68 | taskProvider.refresh(); 69 | this.refresh(); 70 | return; 71 | } 72 | 73 | //default task setting changed 74 | let newCompileOption=await this.GetDefaultTaskOption(); 75 | if(oldCompileOption.toOptionString()!=newCompileOption.toOptionString()){ 76 | taskProvider.refresh(); 77 | } 78 | this.refresh(); 79 | 80 | 81 | 82 | } 83 | getTreeItem(element: FpcItem): vscode.TreeItem { 84 | return element; 85 | } 86 | 87 | getChildren(element?: FpcItem | undefined): vscode.ProviderResult { 88 | 89 | 90 | if (element) { 91 | this.defaultFtpItem=undefined; 92 | let items: FpcItem[] = []; 93 | 94 | element.tasks?.forEach((task) => { 95 | let item = new FpcItem( 96 | 1, 97 | task.label, 98 | vscode.TreeItemCollapsibleState.None, 99 | element.file, 100 | element.fileexist, 101 | task.group?.isDefault, 102 | [task] 103 | ); 104 | items.push(item); 105 | if (item.isDefault) { 106 | this.defaultFtpItem = item; 107 | } 108 | }); 109 | if(!this.defaultFtpItem && items.length>0){ 110 | this.defaultFtpItem=items[0]; 111 | this.defaultFtpItem.description='default'; 112 | this.defaultFtpItem.isDefault=true; 113 | } 114 | return Promise.resolve(items); 115 | 116 | } else { 117 | //root node 118 | 119 | var itemMaps: Map = new Map(); 120 | this.config = vscode.workspace.getConfiguration('tasks', vscode.Uri.file(this.workspaceRoot)); 121 | //create info for pass tasks as pointer 122 | //var info =new TaskInfo(); 123 | //info.tasks=config.tasks; 124 | 125 | 126 | this.config?.tasks?.forEach((e: any) => { 127 | if (e.type === 'fpc') { 128 | if (!itemMaps.has(e.file)) { 129 | itemMaps.set( 130 | e.file, 131 | new FpcItem( 132 | 0, 133 | path.basename(e.file), 134 | vscode.TreeItemCollapsibleState.Expanded, 135 | e.file, 136 | true, 137 | e.group?.isDefault, 138 | [e] 139 | ) 140 | ); 141 | } else { 142 | itemMaps.get(e.file)?.tasks?.push(e); 143 | } 144 | } 145 | 146 | }); 147 | let items: FpcItem[] = []; 148 | 149 | 150 | vscode.workspace.workspaceFolders!.forEach(item => { 151 | let files = fs.readdirSync(item.uri.fsPath); 152 | for (let index = 0; index < files.length; index++) { 153 | 154 | let file = files[index]; 155 | 156 | if (file.toLowerCase().endsWith('.lpr') || file.toLowerCase().endsWith('.dpr')) { 157 | try { 158 | if (itemMaps.has(file)) { 159 | itemMaps.get(file)!.fileexist = true; 160 | continue; 161 | } 162 | 163 | itemMaps.set( 164 | file, 165 | new FpcItem( 166 | 0, 167 | file, 168 | vscode.TreeItemCollapsibleState.Expanded, 169 | file, 170 | true, 171 | false 172 | 173 | ) 174 | ); 175 | 176 | } catch (error) { 177 | vscode.window.showErrorMessage("FPCToolkit:" + Error(error).message); 178 | } 179 | 180 | 181 | } 182 | } 183 | }); 184 | 185 | for (const e of itemMaps.values()) { 186 | items.push(e); 187 | } 188 | 189 | 190 | //}); 191 | // if(info.ischanged){ 192 | // config.update("tasks",info.tasks,vscode.ConfigurationTarget.WorkspaceFolder); 193 | // } 194 | 195 | return Promise.resolve(items); 196 | } 197 | 198 | return Promise.resolve([]); 199 | 200 | } 201 | async GetDefaultTaskOption(): Promise { 202 | 203 | //refresh tasks 204 | await vscode.tasks.fetchTasks({type:'fpc'}); 205 | 206 | let cfg=vscode.workspace.getConfiguration('tasks', vscode.Uri.file(this.workspaceRoot)); 207 | let opt: CompileOption|undefined=undefined; 208 | let is_first=true; 209 | if (cfg?.tasks != undefined) { 210 | for (const e of cfg?.tasks) { 211 | if (e.type === 'fpc') { 212 | if (e.group?.isDefault) { 213 | let def=taskProvider.GetTaskDefinition(e.label); 214 | 215 | opt = new CompileOption(def,this.workspaceRoot); 216 | this.defaultCompileOption=opt; 217 | return opt; 218 | } 219 | if(is_first){ 220 | is_first=false; 221 | let def=taskProvider.GetTaskDefinition(e.label); 222 | opt = new CompileOption(def,this.workspaceRoot); 223 | } 224 | 225 | } 226 | } 227 | } 228 | if(!opt){ 229 | opt=new CompileOption(); 230 | } 231 | this.defaultCompileOption=opt; 232 | return opt; 233 | } 234 | private findJsonDocumentPosition(documentText: string, taskItem: FpcItem) { 235 | // const me = this; 236 | // let inScripts = false; 237 | // let inTasks = false; 238 | // let inTaskLabel: any; 239 | // let scriptOffset = 0; 240 | 241 | 242 | // const visitor: JSONVisitor = 243 | // { 244 | // onError: () => { 245 | // return scriptOffset; 246 | // }, 247 | // onObjectEnd: () => { 248 | // if (inScripts) { 249 | // inScripts = false; 250 | // } 251 | // }, 252 | // onLiteralValue: (value: any, offset: number, _length: number) => { 253 | // if (inTaskLabel) { 254 | // if (typeof value === "string") { 255 | // if (inTaskLabel === "label" || inTaskLabel === "script") { 256 | 257 | // if (taskItem.label === value) { 258 | // scriptOffset = offset; 259 | // } 260 | // } 261 | // } 262 | // inTaskLabel = undefined; 263 | // } 264 | // }, 265 | // onObjectProperty: (property: string, offset: number, _length: number) => { 266 | // if (property === "tasks") { 267 | // inTasks = true; 268 | // if (!inTaskLabel) { // select the script section 269 | // scriptOffset = offset; 270 | // } 271 | // } 272 | // else if ((property === "label" || property === "script") && inTasks && !inTaskLabel) { 273 | // inTaskLabel = "label"; 274 | // if (!inTaskLabel) { // select the script section 275 | // scriptOffset = offset; 276 | // } 277 | // } 278 | // else { // nested object which is invalid, ignore the script 279 | // inTaskLabel = undefined; 280 | // } 281 | // } 282 | // }; 283 | 284 | // visit(documentText, visitor); 285 | 286 | // //log.methodDone("find json document position", 3, " ", false, [["position", scriptOffset]]); 287 | // return scriptOffset; 288 | return documentText.indexOf('"label": "'+taskItem.label+'"'); 289 | } 290 | private async open(selection: FpcItem) { 291 | 292 | let taskfile = vscode.Uri.file(path.join(this.workspaceRoot, '.vscode', 'tasks.json')) 293 | 294 | fs.existsSync(taskfile.fsPath) 295 | { 296 | const document: vscode.TextDocument = await vscode.workspace.openTextDocument(taskfile); 297 | const offset = this.findJsonDocumentPosition(document.getText(), selection); 298 | const position = document.positionAt(offset); 299 | await vscode.window.showTextDocument(document, { selection: new vscode.Selection(position, position) }); 300 | } 301 | } 302 | 303 | } 304 | 305 | export class FpcItem extends vscode.TreeItem { 306 | 307 | 308 | constructor( 309 | public readonly level: number, 310 | public readonly label: string, 311 | public readonly collapsibleState: vscode.TreeItemCollapsibleState, 312 | public readonly file: string, 313 | public fileexist: boolean, 314 | public isDefault: boolean, 315 | public tasks?: any[] 316 | ) { 317 | super(label, collapsibleState); 318 | if (level === 0) { 319 | this.contextValue = 'fpcproject'; 320 | } else { 321 | this.contextValue = 'fpcbuild'; 322 | } 323 | this.tooltip = `${basename(this.label)} `; 324 | if (this.level > 0) { 325 | this.description = this.isDefault ? 'default' : ''; 326 | 327 | const command = { 328 | command: "FpcProjectExplorer.open", // commandId is a string that contains the registered id ('myExtension.debugMessage') 329 | title: '', 330 | arguments: [this] 331 | }; 332 | this.command = command; 333 | } 334 | 335 | this.iconPath=this.level? new vscode.ThemeIcon('wrench'):path.join(__filename, '..','..', 'images','pascal-project.png'); 336 | 337 | //https://code.visualstudio.com/api/references/icons-in-labels 338 | 339 | //this.command!.command= "workbench.action.tasks.configureTaskRunner"; 340 | //this.command!.arguments?.push(this.id); 341 | 342 | } 343 | 344 | 345 | // iconPath = { 346 | // light: this.level?'$(gripper)':path.join(__filename, '..','..', 'images', this.level ? 'build.png' : 'pascal-project.png'), 347 | // dark: path.join(__filename, '..','..', 'images', this.label ? 'build.png' : 'pascal-project.png') 348 | // }; 349 | 350 | 351 | } -------------------------------------------------------------------------------- /src/providers/task.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import * as vscode from 'vscode'; 6 | import { CompileOption } from '../languageServer/options'; 7 | import * as ChildProcess from "child_process"; 8 | import path = require('path'); 9 | import { TerminalEscape, TE_Style } from '../common/escape'; 10 | import * as fs from 'fs'; 11 | import { client } from '../extension'; 12 | import { DiagnosticSeverity } from 'vscode'; 13 | 14 | export class BuildOption { 15 | targetOS?: string; 16 | targetCPU?: string; 17 | customOptions?: string[]; 18 | libPath?: string[]; 19 | outputFile?: string; 20 | unitOutputDir?: string; 21 | optimizationLevel?: number; 22 | searchPath?: string[]; 23 | syntaxMode?: string; 24 | forceRebuild?: boolean = false; 25 | msgIgnore?: Number[]; 26 | }; 27 | 28 | export class BuildEvent{ 29 | before_build?: string[]; 30 | after_build_success?:string[]; 31 | after_build_failure?:string[]; 32 | } 33 | 34 | export class FpcTaskDefinition implements vscode.TaskDefinition { 35 | [name: string]: any; 36 | readonly type: string = 'fpc'; 37 | file?: string; 38 | cwd?: string; 39 | cleanExt?: string; 40 | inherited?: string; 41 | buildOption?: BuildOption; 42 | buildEvent?:BuildEvent; 43 | } 44 | 45 | 46 | export class FpcTaskProvider implements vscode.TaskProvider { 47 | static FpcTaskType = 'fpc'; 48 | private defineMap: Map = new Map(); 49 | public taskMap: Map = new Map(); 50 | public GetTaskDefinition(name: string): FpcTaskDefinition | undefined { 51 | let result = this.defineMap.get(name); 52 | if (result && result.inherited) { 53 | let base = this.defineMap.get(result.inherited); 54 | if (base) { 55 | let realDefinition = new FpcTaskDefinition(); 56 | this.mergeDefinition(base, realDefinition); 57 | this.mergeDefinition(result, realDefinition); 58 | return realDefinition; 59 | 60 | } 61 | } 62 | return result; 63 | } 64 | constructor(private workspaceRoot: string, private cwd: string | undefined = undefined) { 65 | } 66 | 67 | public async clean() { 68 | this.defineMap.clear(); 69 | this.taskMap.clear(); 70 | } 71 | public async provideTasks(): Promise { 72 | return this.getTasks(); 73 | } 74 | 75 | public resolveTask(_task: vscode.Task): vscode.Task | undefined { 76 | if (this.taskMap.has(_task.name)) { 77 | let task = this.taskMap.get(_task.name); 78 | task!.definition = _task.definition; 79 | return task; 80 | } else { 81 | const file: string = _task.definition.file; 82 | if (file) { 83 | const definition: FpcTaskDefinition = _task.definition; 84 | if (_task.definition.cwd) { 85 | this.cwd = this.workspaceRoot + '/' + _task.definition.cwd; 86 | } 87 | let task = this.getTask(_task.name, definition.file, definition); 88 | this.taskMap.set(_task.name, task); 89 | return task; 90 | } 91 | } 92 | 93 | return undefined; 94 | } 95 | 96 | private async getTasks(): Promise { 97 | return []; 98 | } 99 | private mergeDefinition(from: FpcTaskDefinition, to: FpcTaskDefinition) { 100 | to.file = to.file ?? from.file; 101 | to.cwd = to.cwd ?? from.cwd; 102 | to.cleanExt = to.cleanExt ?? from.cleanExt; 103 | if (from.buildOption != undefined) { 104 | if (to.buildOption === undefined) { 105 | to.buildOption = Object.assign({}, from.buildOption); 106 | } 107 | else { 108 | to.buildOption.customOptions = ([] as string[]).concat(from.buildOption.customOptions ?? [], to.buildOption.customOptions ?? []); 109 | to.buildOption.libPath = ([] as string[]).concat(from.buildOption.libPath ?? [], to.buildOption.libPath ?? []); 110 | to.buildOption.searchPath = ([] as string[]).concat(from.buildOption.searchPath ?? [], to.buildOption.searchPath ?? []); 111 | to.buildOption.msgIgnore = ([] as Number[]).concat(from.buildOption.msgIgnore ?? [], to.buildOption.msgIgnore ?? []); 112 | 113 | to.buildOption.optimizationLevel = to.buildOption.optimizationLevel ?? from.buildOption.optimizationLevel; 114 | to.buildOption.outputFile = to.buildOption.outputFile ?? from.buildOption.outputFile; 115 | to.buildOption.syntaxMode = to.buildOption.syntaxMode ?? from.buildOption.syntaxMode; 116 | to.buildOption.targetCPU = to.buildOption.targetCPU ?? from.buildOption.targetCPU; 117 | to.buildOption.targetOS = to.buildOption.targetOS ?? from.buildOption.targetOS; 118 | to.buildOption.unitOutputDir = to.buildOption.unitOutputDir ?? from.buildOption.unitOutputDir; 119 | to.buildOption.forceRebuild = to.buildOption.forceRebuild ?? from.buildOption.forceRebuild; 120 | 121 | } 122 | } 123 | 124 | } 125 | public getTask(name: string, file?: string, definition?: FpcTaskDefinition): vscode.Task { 126 | // if (definition?.inherited) { 127 | // let pdefine = this.defineMap.get(definition.inherited); 128 | // if (pdefine) { 129 | // let realDefinition = new FpcTaskDefinition(); 130 | // this.mergeDefinition(definition, realDefinition); 131 | // this.mergeDefinition(pdefine, realDefinition); 132 | // this.defineMap.set(name, realDefinition); 133 | // let task = new FpcTask(this.cwd ? this.cwd : this.workspaceRoot, name, file!, definition, realDefinition); 134 | // return task; 135 | // } 136 | 137 | // } 138 | this.defineMap.set(name, definition!); 139 | let task = new FpcTask(this.cwd ? this.cwd : this.workspaceRoot, name, file!, definition!); 140 | 141 | 142 | // task.presentationOptions.clear = true; 143 | // task.presentationOptions.echo = true; 144 | // task.presentationOptions.focus = false; 145 | // task.presentationOptions.showReuseMessage = false; 146 | // task.presentationOptions.reveal = vscode.TaskRevealKind.Always; 147 | // task.presentationOptions.panel = vscode.TaskPanelKind.Shared; 148 | // task.presentationOptions.revealProblems='onProblem'; 149 | //(task.presentationOptions as any)["revealProblems"]="onProblem"; 150 | 151 | //task.problemMatchers.push('$fpc'); 152 | 153 | 154 | return task; 155 | } 156 | 157 | public refresh() { 158 | client.restart(); 159 | } 160 | } 161 | 162 | export enum BuildMode { 163 | normal, 164 | rebuild 165 | } 166 | export class FpcTask extends vscode.Task { 167 | private _BuildMode: BuildMode = BuildMode.normal; 168 | public get BuildMode(): BuildMode { 169 | return this._BuildMode; 170 | } 171 | public set BuildMode(value: BuildMode) { 172 | this._BuildMode = value; 173 | } 174 | constructor(cwd: string, name: string, file: string, taskDefinition: FpcTaskDefinition) { 175 | 176 | super( 177 | taskDefinition, 178 | vscode.TaskScope.Workspace, 179 | `${name}`, 180 | FpcTaskProvider.FpcTaskType, 181 | //new vscode.ShellExecution(`${fpcpath} ${taskDefinition.file} ${buildOptionString}`) 182 | new FpcCustomExecution(async (): Promise => { 183 | // // When the task is executed, this callback will run. Here, we setup for running the task. 184 | // let terminal = new FpcBuildTaskTerminal(workspaceRoot, fpcpath!); 185 | //terminal.args = `${taskDefinition?.file} ${buildOptionString}`.split(' '); 186 | 187 | //taskProvider.GetTaskDefinition() 188 | let buildOptionString: string = ''; 189 | let realDefinition=taskProvider.GetTaskDefinition(name); 190 | if (realDefinition === undefined) { 191 | realDefinition = taskDefinition; 192 | } 193 | if (realDefinition?.buildOption) { 194 | let opt: CompileOption = new CompileOption(realDefinition); 195 | buildOptionString = opt.toOptionString(); 196 | } 197 | if (!buildOptionString) { 198 | buildOptionString = ""; 199 | } 200 | 201 | if (!realDefinition) { 202 | realDefinition = { 203 | type: FpcTaskProvider.FpcTaskType, 204 | file: file, 205 | 206 | }; 207 | 208 | } 209 | buildOptionString += '-vq '; //show message numbers 210 | 211 | let fpcpath = process.env['PP'];// configuration.get('env.PP'); 212 | if (fpcpath === '') { 213 | fpcpath = 'fpc'; 214 | } 215 | 216 | let terminal = new FpcBuildTaskTerminal(cwd, fpcpath!); 217 | if(taskDefinition.buildEvent){ 218 | if(taskDefinition.buildEvent.before_build){ 219 | let commands=taskDefinition.buildEvent.before_build; 220 | terminal.event_before_build=()=>{ 221 | for (const cmd of commands) { 222 | let result=ChildProcess.execSync(cmd); 223 | terminal.emit(result.toString()) 224 | } 225 | } 226 | } 227 | if(taskDefinition.buildEvent.after_build_failure || taskDefinition.buildEvent.after_build_success){ 228 | let commands_failure=taskDefinition.buildEvent.after_build_failure; 229 | let commands_success=taskDefinition.buildEvent.after_build_success; 230 | terminal.event_after_build=(success)=>{ 231 | if(success && commands_success){ 232 | for (const cmd of commands_success) { 233 | let result=ChildProcess.execSync(cmd); 234 | terminal.emit(result.toString()) 235 | } 236 | }else if(commands_failure) 237 | for (const cmd of commands_failure) { 238 | let result=ChildProcess.execSync(cmd); 239 | terminal.emit(result.toString()) 240 | } 241 | 242 | } 243 | 244 | } 245 | 246 | } 247 | 248 | terminal.args = `${taskDefinition?.file} ${buildOptionString}`.split(' '); 249 | if (this._BuildMode == BuildMode.rebuild) { 250 | terminal.args.push('-B'); 251 | } 252 | return terminal; 253 | 254 | }) 255 | ); 256 | //this.TaskBuildOptionString = buildOptionString; 257 | } 258 | 259 | 260 | } 261 | 262 | class FpcCustomExecution extends vscode.CustomExecution { 263 | 264 | } 265 | export var diagCollection: vscode.DiagnosticCollection = vscode.languages.createDiagnosticCollection('fpc'); 266 | 267 | class FpcBuildTaskTerminal implements vscode.Pseudoterminal, vscode.TerminalExitStatus { 268 | private writeEmitter = new vscode.EventEmitter(); 269 | onDidWrite: vscode.Event = this.writeEmitter.event; 270 | private closeEmitter = new vscode.EventEmitter(); 271 | onDidClose: vscode.Event = this.closeEmitter.event; 272 | 273 | public event_before_build?:()=>void; 274 | public event_after_build?:(success:boolean)=>void; 275 | 276 | private process?: ChildProcess.ChildProcess; 277 | protected buffer: string = ""; 278 | protected errbuf: string = ""; 279 | 280 | private diagMaps: Map; 281 | public args: string[] = []; 282 | 283 | constructor(private cwd: string, private fpcpath: string) { 284 | this.diagMaps = new Map(); 285 | this.onDidClose((e) => { 286 | //vscode.window.showInformationMessage('onDidClose'); 287 | }); 288 | } 289 | code: number | undefined; 290 | 291 | // private static inst?: FpcBuildTaskTerminal; 292 | // static getInstance(workspaceRoot?: string, fpcpath?: string): FpcBuildTaskTerminal { 293 | // if (FpcBuildTaskTerminal.inst) { 294 | // return FpcBuildTaskTerminal.inst; 295 | // } else { 296 | // FpcBuildTaskTerminal.inst = new FpcBuildTaskTerminal(workspaceRoot!, fpcpath!); 297 | // return FpcBuildTaskTerminal.inst; 298 | // } 299 | 300 | // } 301 | clear() { 302 | 303 | } 304 | open(initialDimensions: vscode.TerminalDimensions | undefined): void { 305 | //vscode.window.createTerminal() 306 | // At this point we can start using the terminal. 307 | this.doBuild(); 308 | } 309 | 310 | close(): void { 311 | 312 | } 313 | 314 | 315 | async buildend() { 316 | let units = Array.from(this.diagMaps.keys()); 317 | 318 | // The terminal has been closed. Shutdown the build. 319 | diagCollection.clear(); 320 | let has_error: boolean = false; 321 | for (const iter of this.diagMaps) { 322 | let key = iter[0]; 323 | let item = iter[1]; 324 | let uri: vscode.Uri | undefined = undefined; 325 | if (fs.existsSync(key)) { 326 | uri = vscode.Uri.file(key); 327 | } 328 | if (!uri) { 329 | let unit = key.split(".")[0]; 330 | 331 | let unitpaths = await client.getUnitPath([unit]); 332 | if (unitpaths.length < 1) { 333 | return; 334 | } 335 | let unitpath = unitpaths[0]; 336 | //let uri:vscode.Uri|undefined=vscode.Uri.file(unitpath); 337 | if (unitpath == '') { 338 | uri = this.findFile(key)!; 339 | } else { 340 | uri = vscode.Uri.file(unitpath); 341 | } 342 | } 343 | 344 | if (uri) { 345 | diagCollection.set(uri, item); 346 | } else { 347 | diagCollection.set(vscode.Uri.file(key), item); 348 | } 349 | if (!has_error) { 350 | 351 | item.forEach((d) => { 352 | if (d.severity === 0) { 353 | has_error = true; 354 | } 355 | }); 356 | } 357 | } 358 | 359 | if (has_error) { 360 | vscode.commands.executeCommand('workbench.actions.view.problems'); 361 | } 362 | } 363 | findFile(filename: string): vscode.Uri | undefined { 364 | 365 | let f = path.join(this.cwd, filename); 366 | if (fs.existsSync(f)) { 367 | return vscode.Uri.file(f); 368 | } 369 | for (let index = 0; index < this.args.length; index++) { 370 | const e = this.args[index]; 371 | if (e.startsWith('-Fu')) { 372 | let f2 = e.substring(3); 373 | if (f2.startsWith('.')) { 374 | f = path.join(this.cwd, f2, filename); 375 | } else { 376 | f = path.join(f2, filename); 377 | } 378 | if (fs.existsSync(f)) { 379 | return vscode.Uri.file(f); 380 | } 381 | } 382 | } 383 | return undefined; 384 | } 385 | 386 | 387 | private async doBuild(): Promise { 388 | return new Promise((resolve) => { 389 | 390 | this.buffer = ""; 391 | this.errbuf = ""; 392 | this.diagMaps.clear(); 393 | if(this.event_before_build){ 394 | this.event_before_build(); 395 | } 396 | this.emit(TerminalEscape.apply({ msg: `${this.fpcpath} ${this.args.join(' ')}\r\n`, style: [TE_Style.Bold] })); 397 | this.process = ChildProcess.spawn(this.fpcpath, this.args, { cwd: this.cwd }); 398 | 399 | this.process.stdout?.on('data', this.stdout.bind(this)); 400 | this.process.stderr?.on('data', this.stderr.bind(this)); 401 | this.process.on('close', (code) => { 402 | 403 | this.writeEmitter.fire(`Exited with code ${code}.\r\nBuild complete. \r\n\r\n`); 404 | this.buildend().then(() => { 405 | this.closeEmitter.fire(code); 406 | }); 407 | if(this.event_after_build){ 408 | this.event_after_build(code==0); 409 | } 410 | //This is a exitcode,not zero meens failure. 411 | 412 | 413 | resolve(0); 414 | }); 415 | 416 | }); 417 | } 418 | 419 | 420 | emit(msg: string) { 421 | this.writeEmitter.fire(msg + '\r\n'); 422 | } 423 | stdout(data: any) { 424 | if (typeof data === "string") { 425 | this.buffer += data; 426 | } 427 | else { 428 | this.buffer += data.toString("utf8"); 429 | } 430 | const end = this.buffer.lastIndexOf('\n'); 431 | if (end !== -1) { 432 | this.onOutput(this.buffer.substr(0, end)); 433 | this.buffer = this.buffer.substr(end + 1); 434 | } 435 | // if (this.buffer.length) { 436 | // this.emit(this.buffer); 437 | // } 438 | } 439 | 440 | stderr(data: any) { 441 | if (typeof data === "string") { 442 | this.emit(TerminalEscape.apply({ msg: data, style: [TE_Style.Yellow] })); 443 | 444 | } 445 | else { 446 | this.emit(TerminalEscape.apply({ msg: data.toString("utf8"), style: [TE_Style.Yellow] })); 447 | } 448 | } 449 | getDiagnosticSeverity(level: string) { 450 | switch (level) { 451 | case 'Fatal': 452 | case 'Error': 453 | return vscode.DiagnosticSeverity.Error; 454 | case 'Warning': 455 | return vscode.DiagnosticSeverity.Warning; 456 | case 'Note': 457 | return vscode.DiagnosticSeverity.Information; 458 | case 'Hint': 459 | return vscode.DiagnosticSeverity.Hint; 460 | default: 461 | return vscode.DiagnosticSeverity.Information; 462 | } 463 | } 464 | onOutput(lines: string) { 465 | let ls = lines.split('\n'); 466 | let cur_file = ""; 467 | let reg = /^(([-:\w\\\/]+)\.(p|pp|pas|lpr|dpr|inc))\(((\d+)(\,(\d+))?)\)\s(Fatal|Error|Warning|Note|Hint): \((\d+)\) (.*)/ 468 | ls.forEach(line => { 469 | 470 | let matchs = reg.exec(line); 471 | 472 | if (matchs) { 473 | 474 | let ln = Number(matchs[5]); 475 | let col = Number(matchs[7]); 476 | let file = matchs[1]; 477 | let unit = matchs[2]; 478 | let level = matchs[8]; 479 | let msgcode = matchs[9]; 480 | let msg = matchs[10]; 481 | // this.emit( 482 | // TerminalEscape.apply({ msg: file+"("+ln+','+col +") ", style: TE_Style.Blue })+ 483 | // TerminalEscape.apply({ msg: level+":"+msg, style: TE_Style.Red }) 484 | // ); 485 | 486 | let diag = new vscode.Diagnostic( 487 | new vscode.Range(new vscode.Position(ln - 1, col - 1), new vscode.Position(ln - 1, col - 1)), 488 | msg, 489 | this.getDiagnosticSeverity(level) 490 | ); 491 | diag.code = Number.parseInt(msgcode); 492 | 493 | // if(msg.match(/ Local variable ".*?".*?(?:not|never) used/)) 494 | // { 495 | // diag.code='variable-not-used'; 496 | // } 497 | let basename = path.basename(file); 498 | // if((cur_file=="")||(path.basename(cur_file)!=path.basename(file))){ 499 | // cur_file=file; 500 | // } 501 | if (this.diagMaps?.has(basename)) { 502 | 503 | this.diagMaps.get(basename)?.push(diag); 504 | } else { 505 | 506 | this.diagMaps.set(basename, [diag]); 507 | 508 | } 509 | if (diag.severity == DiagnosticSeverity.Error) { 510 | this.emit(TerminalEscape.apply({ msg: line, style: [TE_Style.Red] })); 511 | } else { 512 | this.emit(TerminalEscape.apply({ msg: line, style: [TE_Style.Cyan] })); 513 | } 514 | 515 | } else if (line.startsWith('Error:') || line.startsWith('Fatal:')) { //Fatal|Error|Warning|Note 516 | this.emit(TerminalEscape.apply({ msg: line, style: [TE_Style.Red] })); 517 | 518 | } else if (line.startsWith('Warning:')) { 519 | this.emit(TerminalEscape.apply({ msg: line, style: [TE_Style.BrightYellow] })); 520 | } 521 | else { 522 | this.emit(line); 523 | } 524 | }); 525 | } 526 | 527 | } 528 | 529 | export let taskProvider: FpcTaskProvider; 530 | 531 | if (vscode.workspace.workspaceFolders) { 532 | const workspaceRoot = vscode.workspace.workspaceFolders[0].uri.fsPath; 533 | taskProvider = new FpcTaskProvider(workspaceRoot); 534 | } 535 | 536 | -------------------------------------------------------------------------------- /syntaxes/fpc.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | dpr 8 | lpr 9 | pp 10 | pas 11 | 12 | foldingStartMarker 13 | \b(?i:(function|package|procedure|try|type))\b 14 | foldingStopMarker 15 | \b(?i:(end))\b 16 | keyEquivalent 17 | ^~P 18 | name 19 | Pascal 20 | patterns 21 | 22 | 23 | match 24 | \b(?i:(absolute|abstract|all|and|and_then|array|as|asm|assembler|attribute|begin|bindable|case|class|const|constructor|destructor|delay|div|do|downto|else|end|except|export|exports|external|far|file|finalization|finally|for|forward|generic|goto|if|inc|implementation|import|in|index|inherited|initialization|inline|interface|interrupt|is|label|library|mod|module|near|nil|not|object|of|only|operator|or|or_else|otherwise|out|override|overload|packed|pow|private|property|protected|public|published|qualified|record|repeat|resident|restricted|segment|set|shl|shr|then|to|try|type|unit|until|uses|value|var|view|virtual|while|with|xor|write|writeln|specialize))\b 25 | name 26 | keyword.control.pascal 27 | 28 | 29 | captures 30 | 31 | 1 32 | 33 | name 34 | storage.type.prototype.pascal 35 | 36 | 2 37 | 38 | name 39 | entity.name.function.prototype.pascal 40 | 41 | 42 | match 43 | \b(?i:(function|procedure))\b\s+(\w+(\.\w+)?)(\(.*?\))?;\s*(?=(?i:attribute|forward|external)) 44 | name 45 | meta.function.prototype.pascal 46 | 47 | 48 | 49 | captures 50 | 51 | 1 52 | 53 | name 54 | storage.type.function.pascal 55 | 56 | 2 57 | 58 | name 59 | entity.name.function.pascal 60 | 61 | 62 | match 63 | \b(?i:(function|procedure|program))\b\s+(\w+(\.\w+)?) 64 | name 65 | meta.function.pascal 66 | 67 | 68 | 69 | captures 70 | 71 | 1 72 | 73 | name 74 | storage.type.function.pascal 75 | 76 | 2 77 | 78 | name 79 | entity.name.function.pascal 80 | 81 | 82 | match 83 | \b(?i:(Shortint|Integer|Longint|Byte|Word|Boolean|WordBool|LongBool|ByteBool|Real|Single|Double|Extended|Comp|String|Char|Length|Upcase|textbackground|textcolor|gotoxy|crt|clrscr|readkey|read|readln))\b 84 | name 85 | meta.function.pascal 86 | 87 | 88 | 89 | 90 | match 91 | \b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\b 92 | name 93 | constant.numeric.pascal 94 | 95 | 96 | captures 97 | 98 | 1 99 | 100 | name 101 | punctuation.definition.comment.pascal 102 | 103 | 104 | match 105 | (--).*$\n? 106 | name 107 | comment.line.double-dash.pascal.one 108 | 109 | 110 | captures 111 | 112 | 1 113 | 114 | name 115 | punctuation.definition.comment.pascal 116 | 117 | 118 | match 119 | (//).*$\n? 120 | name 121 | comment.line.double-slash.pascal.two 122 | 123 | 124 | begin 125 | \(\* 126 | captures 127 | 128 | 0 129 | 130 | name 131 | punctuation.definition.comment.pascal 132 | 133 | 134 | end 135 | \*\) 136 | name 137 | comment.block.pascal.one 138 | 139 | 140 | begin 141 | \{ 142 | captures 143 | 144 | 0 145 | 146 | name 147 | punctuation.definition.comment.pascal 148 | 149 | 150 | end 151 | \} 152 | name 153 | comment.block.pascal.two 154 | 155 | 156 | applyEndPatternLast 157 | 1 158 | begin 159 | ' 160 | beginCaptures 161 | 162 | 0 163 | 164 | name 165 | punctuation.definition.string.begin.pascal 166 | 167 | 168 | end 169 | ' 170 | endCaptures 171 | 172 | 0 173 | 174 | name 175 | punctuation.definition.string.end.pascal 176 | 177 | 178 | name 179 | string.quoted.single.pascal 180 | patterns 181 | 182 | 183 | match 184 | '' 185 | name 186 | constant.character.escape.apostrophe.pascal 187 | 188 | 189 | 190 | 191 | scopeName 192 | source.pascal 193 | uuid 194 | F42FA544-6B1C-11D9-9517-000D93589AF6 195 | 196 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "suppressImplicitAnyIndexErrors":true, 10 | "sourceMap": true, 11 | "rootDir": "src", 12 | "strict": true /* enable all strict type-checking options */ 13 | /* Additional Checks */ 14 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 15 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 16 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".vscode-test" 21 | ] 22 | } 23 | --------------------------------------------------------------------------------