├── .gitignore
├── .tool-versions
├── .vscode
└── launch.json
├── .vscodeignore
├── CHANGELOG.md
├── README.md
├── images
├── logo.png
└── logo.svg
├── language-configuration.json
├── package-lock.json
├── package.json
├── snippets
└── mint.json
├── src
├── commands.ts
├── extension.ts
├── formatter.ts
└── utils.ts
├── syntaxes
├── mint.tmLanguage.json
└── mint.tmLanguage.yaml
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.vsix
3 | out
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | nodejs 20.9.0
2 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that launches the extension 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": "Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "runtimeExecutable": "${execPath}",
13 | "args": ["--extensionDevelopmentPath=${workspaceFolder}"]
14 | }
15 | ],
16 | "log": true
17 | }
18 |
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | .gitignore
4 | vsc-extension-quickstart.md
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Mint VS Code Changelog
2 |
3 | ## 0.6.0
4 |
5 | - Add line comment ([#23](https://github.com/mint-lang/mint-vscode/pull/23))
6 | - Add missing module snippet ([#24](https://github.com/mint-lang/mint-vscode/pull/24))
7 |
8 | ## 0.5.0
9 |
10 | - Better syntax highlighting ([#21](https://github.com/mint-lang/mint-vscode/pull/21))
11 |
12 | ## 0.4.0
13 |
14 | - Added support for language server ([#20](https://github.com/mint-lang/mint-vscode/pull/20))
15 |
16 | ## 0.3.3
17 |
18 | - Highlight `const` keyword ([#18](https://github.com/mint-lang/mint-vscode/pull/18))
19 |
20 | ## 0.3.2
21 |
22 | - Highlight `using` keyword ([#16](https://github.com/mint-lang/mint-vscode/pull/16))
23 |
24 | ## 0.3.1
25 |
26 | - Highlight `enum` keyword ([#15](https://github.com/mint-lang/mint-vscode/pull/15))
27 | - Hide Command Palette commands when not in a Mint project ([#14](https://github.com/mint-lang/mint-vscode/pull/14))
28 |
29 | ## 0.3.0
30 |
31 | - Add Mint CLI commands to command palette ([#10](https://github.com/mint-lang/mint-vscode/pull/10))
32 |
33 | ## 0.2.0
34 |
35 | - Add formatting support ([#7](https://github.com/mint-lang/mint-vscode/pull/7))
36 |
37 | ## 0.1.0
38 |
39 | - Fix broken HTML highlighting ([#1](https://github.com/mint-lang/mint-vscode/pull/1))
40 |
41 | ## 0.0.2
42 |
43 | - Initial Fork
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mint VS Code Support
2 |
3 | ### This extension provides support for the [Mint](https://mint-lang.com) programming language.
4 |
5 | ### Features
6 |
7 | - Simple Syntax Highlighting
8 | - Snippets
9 | - Formatting
10 | - Commands
11 |
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mint-lang/mint-vscode/9b0c8b54f80c9e32bb479ae8737b2c68ec275dd4/images/logo.png
--------------------------------------------------------------------------------
/images/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
146 |
--------------------------------------------------------------------------------
/language-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 | }
26 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mint",
3 | "version": "0.7.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "mint",
9 | "version": "0.7.0",
10 | "hasInstallScript": true,
11 | "license": "MIT",
12 | "dependencies": {
13 | "vscode-languageclient": "^6.1.3"
14 | },
15 | "devDependencies": {
16 | "@types/node": "^14.11.2",
17 | "@types/vscode": "^1.77.0",
18 | "js-yaml": "^3.14.0",
19 | "typescript": "^4.0.3"
20 | },
21 | "engines": {
22 | "vscode": "^1.77.0"
23 | }
24 | },
25 | "node_modules/@types/node": {
26 | "version": "14.11.2",
27 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz",
28 | "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==",
29 | "dev": true
30 | },
31 | "node_modules/@types/vscode": {
32 | "version": "1.96.0",
33 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz",
34 | "integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==",
35 | "dev": true
36 | },
37 | "node_modules/argparse": {
38 | "version": "1.0.10",
39 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
40 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
41 | "dev": true,
42 | "dependencies": {
43 | "sprintf-js": "~1.0.2"
44 | }
45 | },
46 | "node_modules/esprima": {
47 | "version": "4.0.1",
48 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
49 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
50 | "dev": true,
51 | "bin": {
52 | "esparse": "bin/esparse.js",
53 | "esvalidate": "bin/esvalidate.js"
54 | },
55 | "engines": {
56 | "node": ">=4"
57 | }
58 | },
59 | "node_modules/js-yaml": {
60 | "version": "3.14.0",
61 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
62 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
63 | "dev": true,
64 | "dependencies": {
65 | "argparse": "^1.0.7",
66 | "esprima": "^4.0.0"
67 | },
68 | "bin": {
69 | "js-yaml": "bin/js-yaml.js"
70 | }
71 | },
72 | "node_modules/semver": {
73 | "version": "6.3.0",
74 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
75 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
76 | "bin": {
77 | "semver": "bin/semver.js"
78 | }
79 | },
80 | "node_modules/sprintf-js": {
81 | "version": "1.0.3",
82 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
83 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
84 | "dev": true
85 | },
86 | "node_modules/typescript": {
87 | "version": "4.0.3",
88 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz",
89 | "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==",
90 | "dev": true,
91 | "bin": {
92 | "tsc": "bin/tsc",
93 | "tsserver": "bin/tsserver"
94 | },
95 | "engines": {
96 | "node": ">=4.2.0"
97 | }
98 | },
99 | "node_modules/vscode-jsonrpc": {
100 | "version": "5.0.1",
101 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz",
102 | "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==",
103 | "engines": {
104 | "node": ">=8.0.0 || >=10.0.0"
105 | }
106 | },
107 | "node_modules/vscode-languageclient": {
108 | "version": "6.1.4",
109 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz",
110 | "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==",
111 | "dependencies": {
112 | "semver": "^6.3.0",
113 | "vscode-languageserver-protocol": "3.15.3"
114 | },
115 | "engines": {
116 | "vscode": "^1.41.0"
117 | }
118 | },
119 | "node_modules/vscode-languageserver-protocol": {
120 | "version": "3.15.3",
121 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz",
122 | "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==",
123 | "dependencies": {
124 | "vscode-jsonrpc": "^5.0.1",
125 | "vscode-languageserver-types": "3.15.1"
126 | }
127 | },
128 | "node_modules/vscode-languageserver-types": {
129 | "version": "3.15.1",
130 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz",
131 | "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ=="
132 | }
133 | },
134 | "dependencies": {
135 | "@types/node": {
136 | "version": "14.11.2",
137 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz",
138 | "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==",
139 | "dev": true
140 | },
141 | "@types/vscode": {
142 | "version": "1.96.0",
143 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz",
144 | "integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==",
145 | "dev": true
146 | },
147 | "argparse": {
148 | "version": "1.0.10",
149 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
150 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
151 | "dev": true,
152 | "requires": {
153 | "sprintf-js": "~1.0.2"
154 | }
155 | },
156 | "esprima": {
157 | "version": "4.0.1",
158 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
159 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
160 | "dev": true
161 | },
162 | "js-yaml": {
163 | "version": "3.14.0",
164 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
165 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
166 | "dev": true,
167 | "requires": {
168 | "argparse": "^1.0.7",
169 | "esprima": "^4.0.0"
170 | }
171 | },
172 | "semver": {
173 | "version": "6.3.0",
174 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
175 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
176 | },
177 | "sprintf-js": {
178 | "version": "1.0.3",
179 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
180 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
181 | "dev": true
182 | },
183 | "typescript": {
184 | "version": "4.0.3",
185 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz",
186 | "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==",
187 | "dev": true
188 | },
189 | "vscode-jsonrpc": {
190 | "version": "5.0.1",
191 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz",
192 | "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A=="
193 | },
194 | "vscode-languageclient": {
195 | "version": "6.1.4",
196 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz",
197 | "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==",
198 | "requires": {
199 | "semver": "^6.3.0",
200 | "vscode-languageserver-protocol": "3.15.3"
201 | }
202 | },
203 | "vscode-languageserver-protocol": {
204 | "version": "3.15.3",
205 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz",
206 | "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==",
207 | "requires": {
208 | "vscode-jsonrpc": "^5.0.1",
209 | "vscode-languageserver-types": "3.15.1"
210 | }
211 | },
212 | "vscode-languageserver-types": {
213 | "version": "3.15.1",
214 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz",
215 | "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ=="
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mint",
3 | "license": "MIT",
4 | "displayName": "Mint",
5 | "description": "VS Code Support for the Mint programming language.",
6 | "version": "0.7.0",
7 | "publisher": "mint-lang",
8 | "repository": {
9 | "url": "https://github.com/mint-lang/mint-vscode"
10 | },
11 | "engines": {
12 | "vscode": "^1.77.0"
13 | },
14 | "activationEvents": [
15 | "onLanguage:mint",
16 | "workspaceContains:**/*.mint",
17 | "onCommand:mint.init"
18 | ],
19 | "main": "./out/src/extension",
20 | "dependencies": {
21 | "vscode-languageclient": "^6.1.3"
22 | },
23 | "devDependencies": {
24 | "@types/node": "^14.11.2",
25 | "@types/vscode": "^1.77.0",
26 | "js-yaml": "^3.14.0",
27 | "typescript": "^4.0.3"
28 | },
29 | "scripts": {
30 | "compile": "echo Compiling... && npm run convert && tsc -p ./",
31 | "convert": "js-yaml syntaxes/mint.tmLanguage.yaml > syntaxes/mint.tmLanguage.json",
32 | "postinstall": "tsc -p ./",
33 | "watch": "tsc -watch -p ./",
34 | "vscode:prepublish": "npm run compile"
35 | },
36 | "icon": "images/logo.png",
37 | "categories": [
38 | "Programming Languages"
39 | ],
40 | "contributes": {
41 | "configuration": {
42 | "type": "object",
43 | "title": "Mint Language Server",
44 | "properties": {
45 | "mint.languageServer.location": {
46 | "type": "string",
47 | "description": "Provide a custom location for the language server binary"
48 | },
49 | "mint.trace.server": {
50 | "scope": "window",
51 | "type": "string",
52 | "enum": ["off","messages","verbose"],
53 | "default": "verbose"
54 | }
55 | }
56 | },
57 | "languages": [
58 | {
59 | "id": "mint",
60 | "aliases": [
61 | "Mint",
62 | "mint"
63 | ],
64 | "extensions": [
65 | ".mint"
66 | ],
67 | "configuration": "./language-configuration.json"
68 | }
69 | ],
70 | "grammars": [
71 | {
72 | "language": "mint",
73 | "scopeName": "source.mint",
74 | "path": "./syntaxes/mint.tmLanguage.json"
75 | }
76 | ],
77 | "snippets": [
78 | {
79 | "language": "mint",
80 | "path": "./snippets/mint.json"
81 | }
82 | ],
83 | "commands": [
84 | {
85 | "command": "mint.build",
86 | "title": "Build production bundle",
87 | "category": "Mint"
88 | },
89 | {
90 | "command": "mint.compile",
91 | "title": "Compile project into single JavaScript file",
92 | "category": "Mint"
93 | },
94 | {
95 | "command": "mint.docs",
96 | "title": "Start documentation server",
97 | "category": "Mint"
98 | },
99 | {
100 | "command": "mint.formatAll",
101 | "title": "Format all files",
102 | "category": "Mint"
103 | },
104 | {
105 | "command": "mint.init",
106 | "title": "Initialize new project",
107 | "category": "Mint"
108 | },
109 | {
110 | "command": "mint.install",
111 | "title": "Install dependencies",
112 | "category": "Mint"
113 | },
114 | {
115 | "command": "mint.loc",
116 | "title": "Count lines of code",
117 | "category": "Mint"
118 | },
119 | {
120 | "command": "mint.start",
121 | "title": "Start development server",
122 | "category": "Mint"
123 | },
124 | {
125 | "command": "mint.test",
126 | "title": "Run tests",
127 | "category": "Mint"
128 | },
129 | {
130 | "command": "mint.version",
131 | "title": "Show current version",
132 | "category": "Mint"
133 | }
134 | ],
135 | "menus": {
136 | "commandPalette": [
137 | {
138 | "command": "mint.build",
139 | "when": "mint:isActivated"
140 | },
141 | {
142 | "command": "mint.compile",
143 | "when": "mint:isActivated"
144 | },
145 | {
146 | "command": "mint.docs",
147 | "when": "mint:isActivated"
148 | },
149 | {
150 | "command": "mint.formatAll",
151 | "when": "mint:isActivated"
152 | },
153 | {
154 | "command": "mint.init"
155 | },
156 | {
157 | "command": "mint.install",
158 | "when": "mint:isActivated"
159 | },
160 | {
161 | "command": "mint.loc",
162 | "when": "mint:isActivated"
163 | },
164 | {
165 | "command": "mint.start",
166 | "when": "mint:isActivated"
167 | },
168 | {
169 | "command": "mint.test",
170 | "when": "mint:isActivated"
171 | },
172 | {
173 | "command": "mint.version",
174 | "when": "mint:isActivated"
175 | }
176 | ]
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/snippets/mint.json:
--------------------------------------------------------------------------------
1 | {
2 | "Main component": {
3 | "prefix": "main",
4 | "body": [
5 | "component Main {",
6 | "\tfun render : Html {",
7 | "\t\t<$0/>",
8 | "\t}",
9 | "}"
10 | ],
11 | "description": "The component named Main is the one that get's rendered on the screen."
12 | },
13 | "Store": {
14 | "prefix": "store",
15 | "body": ["store ${1:StoreName}.Store {", "\t$0", "}"],
16 | "description": "Stores are global containers of application specific data."
17 | },
18 | "Store property": {
19 | "prefix": "prop",
20 | "body": ["property ${1:name} : ${2:Number} = ${0:0}"],
21 | "description": "The property keyword when used in a store defines part of the data that the store contains."
22 | },
23 | "Functions": {
24 | "prefix": "fun",
25 | "body": [
26 | "fun ${1:name}(${2:object} : ${3:String}) : ${4:Void} {",
27 | "\t$0",
28 | "}"
29 | ],
30 | "description": "Functions can be defined on modules, components, stores and providers."
31 | },
32 | "Next Call": {
33 | "prefix": "next",
34 | "body": ["next { state | ${1:name} = ${1:name} + 1 }"],
35 | "description": "Functions can be defined on modules, components, stores and providers."
36 | },
37 | "Render": {
38 | "prefix": "render",
39 | "body": ["fun render : Html {", "\t$0", "}"],
40 | "description": "The render function renders the component into an HTML tree."
41 | },
42 | "HTML Elements": {
43 | "prefix": "div",
44 | "body": ["<${1:div}::${2:stylename}>", "\t$0", "${1:div}>"],
45 | "description": "HTML elements can be written as in standard HTML."
46 | },
47 | "Span Element": {
48 | "prefix": "span",
49 | "body": ["<${1:span}::${2:stylename}>", "\t$0", "${1:span}>"],
50 | "description": "HTML elements can be written as in standard HTML."
51 | },
52 | "Paragraph Element": {
53 | "prefix": "p",
54 | "body": ["<${1:p}::${2:stylename}>", "\t$0", "${1:p}>"],
55 | "description": "HTML elements can be written as in standard HTML."
56 | },
57 | "Title Element": {
58 | "prefix": "h",
59 | "body": ["<${1:h1}::${2:stylename}>", "\t$0", "${1:h1}>"],
60 | "description": "HTML elements can be written as in standard HTML."
61 | },
62 | "Button Element": {
63 | "prefix": "button",
64 | "body": [
65 | "<${1:button}::${2:stylename} ${3:disabled}={${4:disabled}}>",
66 | "\t<{ \"${5:Text}\" }>",
67 | "${1:button}>"
68 | ],
69 | "description": "HTML elements can be written as in standard HTML."
70 | },
71 | "HTML Expressions": {
72 | "prefix": "exp",
73 | "body": ["<{ \"${Message}\" }>"],
74 | "description": "HTML Expressions allows inserting data into HTML elements or components."
75 | },
76 | "Attributes": {
77 | "prefix": "att",
78 | "body": ["{${disabled}}"],
79 | "description": "Attributes are either strings or expressions."
80 | },
81 | "Modules": {
82 | "prefix": "mod",
83 | "body": ["module ${1:ModuleName} {", "\t$0", "}"],
84 | "description": "Modules are kind of containers for a set of relatable functions, usually used to gather functions that relate to a specific type."
85 | },
86 | "Components": {
87 | "prefix": "com",
88 | "body": ["component ${1:ComponentName} {", "\t$0", "}"],
89 | "description": "Components are reusable pieces of code that have specific behavior, styles and content."
90 | },
91 | "Components Tags": {
92 | "prefix": "tag",
93 | "body": ["<${1:Component} ${2:attribute}={${3:value}}/>"],
94 | "description": "Tags that have the name of a component will render that component at the point where the tag is defined."
95 | },
96 | "Events": {
97 | "prefix": "event",
98 | "body": ["${onEvent}={\\event : Html.Event => ${handler}()}"],
99 | "description": "All event handlers are functions, they take an event record and return Void."
100 | },
101 | "Connect": {
102 | "prefix": "con",
103 | "body": ["connect ${1:StoreName}.Store exposing { $0 }"],
104 | "description": "The connect directive lets you connect a component to a store which allows you to call the stores functions and properties without using the stores name."
105 | },
106 | "Style": {
107 | "prefix": "sty",
108 | "body": ["style ${1:base} {", "\t${2:attribute}: ${3:value};", "}"],
109 | "description": "Styles define with CSS how an HTML element looks."
110 | },
111 | "Computed Properties": {
112 | "prefix": "get",
113 | "body": ["get ${1:computedProperty} : ${2:String} {", "\t$0", "}"],
114 | "description": "Computed properties works like regular properties but instead of returning a constant value it can return different values base on the state and the properties."
115 | },
116 | "If": {
117 | "prefix": "if",
118 | "body": [
119 | "if (${1:condition}) {",
120 | "\t${2:value}",
121 | "} else {",
122 | "\t${3:otherValue}",
123 | "}"
124 | ],
125 | "description": "The if...else conditional expression can return two different values based on a condition."
126 | },
127 | "Case": {
128 | "prefix": "case",
129 | "body": [
130 | "case (${1:condition}) {",
131 | "\t${2:match1} => ${3:value1}",
132 | "\t${4:match3} => ${5:value3}",
133 | "\t=> ${6:defaultValue}",
134 | "}"
135 | ],
136 | "description": "A case expression is useful for matching enums or exact values, while also supporting a default value."
137 | },
138 | "Record": {
139 | "prefix": "record",
140 | "body": [
141 | "record ${1:User} {",
142 | "\t${2:name} : ${3:String},",
143 | "\t${4:email} : ${5:String}",
144 | "}"
145 | ],
146 | "description": "Records are object like data structures, that have a fix set of keys and values."
147 | },
148 | "Try": {
149 | "prefix": "try",
150 | "body": [
151 | "try {",
152 | "\t$1",
153 | "} catch ${2:Json}.Error => error {",
154 | "\t$3",
155 | "}"
156 | ],
157 | "description": "try is a control expression for handling synchronous computations that might fail, for example when you are trying to convert an untyped JavaScript object into a typed Record."
158 | },
159 | "Do": {
160 | "prefix": "do",
161 | "body": ["do {", "\t$1", "} catch ${2:Http}.Error => error {", "\t$3", "}"],
162 | "description": "do expressions are for two things: handling asynchronous computations that might fail, for example when loading something with a request, or executing asynchronous expressions sequentially."
163 | },
164 | "Routes": {
165 | "prefix": "routes",
166 | "body": [
167 | "routes {",
168 | "\t/ {",
169 | "\t\t${1:Application.setPage(\"index\")}",
170 | "\t}",
171 | "\t/${2:user}/:${3:id} {",
172 | "\t\t do {",
173 | "\t\t\t${4:Application.setPage(\"show\")}",
174 | "\t\t\t${5:Application.loadUser(id)}",
175 | "\t\t}",
176 | "\t}",
177 | "}"
178 | ],
179 | "description": "In Mint routes of an application are defined at the top level with the routes block."
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/src/commands.ts:
--------------------------------------------------------------------------------
1 | import { runMintCommandAsTask, promiseSeconds } from "./utils";
2 | import * as vscode from "vscode";
3 |
4 | export function mintBuildCommand() {
5 | runMintCommandAsTask("build", "Build production bundle");
6 | }
7 |
8 | export function mintCompileCommand() {
9 | runMintCommandAsTask(
10 | "compile",
11 | "Compile project into single JavaScript file"
12 | );
13 | }
14 |
15 | export function mintDocsCommand() {
16 | runMintCommandAsTask("docs", "Start documentation server");
17 | }
18 |
19 | export function mintFormatAllCommand() {
20 | runMintCommandAsTask("format", "Format all files");
21 | }
22 |
23 | export async function mintInitCommand() {
24 | const projectName = await vscode.window.showInputBox({
25 | prompt: "Type the name of your project",
26 | placeHolder: "mint-project",
27 | });
28 |
29 | const folder = await vscode.window.showOpenDialog({
30 | canSelectFiles: false,
31 | canSelectFolders: true,
32 | canSelectMany: false,
33 | openLabel: "Create project",
34 | });
35 |
36 | const newProjectRoot = `${folder[0].path}/${projectName}`;
37 |
38 | await runMintCommandAsTask(`init ${newProjectRoot}`, "Init a new project");
39 |
40 | await promiseSeconds(2);
41 |
42 | await vscode.commands.executeCommand(
43 | "vscode.openFolder",
44 | vscode.Uri.file(newProjectRoot)
45 | );
46 | }
47 |
48 | export function mintInstallCommand() {
49 | runMintCommandAsTask("install", "Install dependencies");
50 | }
51 |
52 | export function mintCountLinesCommand() {
53 | runMintCommandAsTask("loc", "Count lines of code");
54 | }
55 |
56 | export function mintStartCommand() {
57 | runMintCommandAsTask("start", "Start development server");
58 | }
59 |
60 | export function mintTestCommand() {
61 | runMintCommandAsTask("test", "Run tests");
62 | }
63 |
64 | export function mintVersionCommand() {
65 | runMintCommandAsTask("version", "Show current version");
66 | }
67 |
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | import * as cmd from "./commands";
2 | import * as vscode from "vscode";
3 | import * as fs from "fs";
4 |
5 | import { LanguageClient } from 'vscode-languageclient';
6 | import { MintFormattingProvider } from "./formatter";
7 |
8 | let client: LanguageClient
9 |
10 | export async function activate(
11 | context: vscode.ExtensionContext,
12 | isRestart: boolean = false
13 | ): Promise {
14 | // Set context activated
15 | vscode.commands.executeCommand("setContext", "mint:isActivated", true);
16 |
17 | // Register formatting provider
18 | vscode.languages.registerDocumentFormattingEditProvider(
19 | "mint",
20 | new MintFormattingProvider()
21 | );
22 |
23 | // Register commands
24 | vscode.commands.registerCommand("mint.build", cmd.mintBuildCommand);
25 | vscode.commands.registerCommand("mint.compile", cmd.mintCompileCommand);
26 | vscode.commands.registerCommand("mint.docs", cmd.mintDocsCommand);
27 | vscode.commands.registerCommand("mint.formatAll", cmd.mintFormatAllCommand);
28 | vscode.commands.registerCommand("mint.init", cmd.mintInitCommand);
29 | vscode.commands.registerCommand("mint.install", cmd.mintInstallCommand);
30 | vscode.commands.registerCommand("mint.loc", cmd.mintCountLinesCommand);
31 | vscode.commands.registerCommand("mint.start", cmd.mintStartCommand);
32 | vscode.commands.registerCommand("mint.test", cmd.mintTestCommand);
33 | vscode.commands.registerCommand("mint.version", cmd.mintVersionCommand);
34 |
35 | const binaryLocation : string = vscode.workspace.getConfiguration('mint.languageServer').get('location')
36 |
37 | if (binaryLocation) {
38 | if (fs.existsSync(binaryLocation)) {
39 | // Create the language client
40 | client = new LanguageClient(
41 | 'mint',
42 | 'Mint Language Server',
43 | {
44 | command: binaryLocation,
45 | args: ['tool', 'ls'],
46 | },
47 | {
48 | documentSelector: [
49 | {scheme: 'file', language: 'mint'},
50 | ]
51 | }
52 | );
53 |
54 | // Start the client
55 | context.subscriptions.push(client.start());
56 | } else {
57 | vscode.window.showErrorMessage('Mint binary not found! You specified ' + binaryLocation);
58 | }
59 | }
60 | }
61 |
62 | export async function deactivate(isRestart: boolean = false): Promise {
63 | // Set context deactivated
64 | vscode.commands.executeCommand("setContext", "mint:isActivated", false);
65 |
66 | // Stop the language server client.
67 | if (client) {
68 | client.stop()
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/formatter.ts:
--------------------------------------------------------------------------------
1 | import vscode = require("vscode");
2 | import cp = require("child_process");
3 | import fs = require("fs");
4 |
5 | import { getDirtyFile } from "./utils";
6 |
7 | export class MintFormattingProvider
8 | implements vscode.DocumentFormattingEditProvider {
9 | public provideDocumentFormattingEdits(
10 | document: vscode.TextDocument,
11 | options: vscode.FormattingOptions,
12 | token: vscode.CancellationToken
13 | ): vscode.TextEdit[] | Thenable {
14 | return new Promise((resolve, reject) => {
15 | let file = getDirtyFile(document);
16 |
17 | let res = cp.spawnSync("mint", ["format", file], {
18 | cwd: vscode.workspace.rootPath,
19 | });
20 |
21 | if (res.status !== 0) {
22 | reject(res.error);
23 | } else {
24 | if (!fs.existsSync(file)) {
25 | reject(file + " file not found");
26 | } else {
27 | let content = fs.readFileSync(file, "utf-8");
28 | let range = document.validateRange(
29 | new vscode.Range(
30 | new vscode.Position(0, 0),
31 | new vscode.Position(1000000, 1000000)
32 | )
33 | );
34 | resolve([vscode.TextEdit.replace(range, content)]);
35 | }
36 | }
37 | });
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import fs = require("fs");
2 | import path = require("path");
3 | import os = require("os");
4 | import vscode = require("vscode");
5 |
6 | /**
7 | * Returns temporary file path of edited document.
8 | */
9 | export function getDirtyFile(document: vscode.TextDocument): string {
10 | var dirtyFilePath = path.normalize(
11 | path.join(os.tmpdir(), "vscodemintdirty.mint")
12 | );
13 | fs.writeFileSync(dirtyFilePath, document.getText());
14 | return dirtyFilePath;
15 | }
16 |
17 | export function createAndShowOutputWindow(): vscode.OutputChannel {
18 | var channel = vscode.window.createOutputChannel("mint");
19 | channel.show();
20 | return channel;
21 | }
22 | /**
23 | * Run a mint subcommand as a VSCode task, ie `mint format`
24 | *
25 | * @param subcommand The mint subcommand to run, ie `format`
26 | * @param description The VSCode description to show, ie "Format all files"
27 | */
28 | export function runMintCommandAsTask(
29 | subcommand: string,
30 | description: string
31 | ): Thenable {
32 | return vscode.tasks.executeTask(
33 | new vscode.Task(
34 | { command: "", type: "" },
35 | vscode.TaskScope.Workspace,
36 | description,
37 | "mint",
38 | new vscode.ShellExecution(`mint ${subcommand}`)
39 | )
40 | );
41 | }
42 |
43 | /**
44 | * Wait for a number of seconds
45 | *
46 | * @param seconds The number of seconds to wait before completing
47 | */
48 | export function promiseSeconds(seconds: number): Thenable {
49 | return new Promise((res) => {
50 | setTimeout(res, 1000 * seconds);
51 | });
52 | }
53 |
--------------------------------------------------------------------------------
/syntaxes/mint.tmLanguage.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
3 | "name": "Mint",
4 | "scopeName": "source.mint",
5 | "patterns": [
6 | {
7 | "include": "#comments"
8 | },
9 | {
10 | "include": "#html"
11 | },
12 | {
13 | "include": "#regex"
14 | },
15 | {
16 | "include": "#style"
17 | },
18 | {
19 | "include": "#js"
20 | },
21 | {
22 | "include": "#routes"
23 | },
24 | {
25 | "include": "#keywords"
26 | },
27 | {
28 | "include": "#strings"
29 | },
30 | {
31 | "include": "#directives"
32 | }
33 | ],
34 | "repository": {
35 | "comments": {
36 | "patterns": [
37 | {
38 | "name": "comment.block.mint",
39 | "begin": "/\\*",
40 | "end": "\\*/"
41 | },
42 | {
43 | "match": "((//).*)$",
44 | "captures": {
45 | "1": {
46 | "name": "comment.line.double-slash.mint"
47 | }
48 | }
49 | }
50 | ]
51 | },
52 | "css": {
53 | "patterns": [
54 | {
55 | "match": "//",
56 | "comment": "invalidate as css comment block"
57 | },
58 | {
59 | "include": "#style-nesting"
60 | },
61 | {
62 | "include": "source.css#pseudo-classes"
63 | },
64 | {
65 | "include": "source.css#pseudo-elements"
66 | },
67 | {
68 | "include": "source.css.scss#general"
69 | },
70 | {
71 | "include": "source.css.scss#selectors"
72 | },
73 | {
74 | "include": "source.css.scss#properties"
75 | },
76 | {
77 | "include": "source.css.scss#at_rule_import"
78 | },
79 | {
80 | "include": "source.css.scss#at_rule_media"
81 | },
82 | {
83 | "include": "source.css.scss#at_rule_charset"
84 | },
85 | {
86 | "include": "source.css.scss#at_rule_namespace"
87 | },
88 | {
89 | "include": "source.css.scss#at_rule_fontface"
90 | },
91 | {
92 | "include": "source.css.scss#at_rule_page"
93 | },
94 | {
95 | "include": "source.css.scss#at_rule_supports"
96 | },
97 | {
98 | "begin": "(?<=^|\\s)(@)(?:-(?:webkit|moz)-)?keyframes\\b",
99 | "beginCaptures": {
100 | "0": {
101 | "name": "keyword.control.at-rule.keyframes.scss"
102 | },
103 | "1": {
104 | "name": "punctuation.definition.keyword.scss"
105 | }
106 | },
107 | "end": "(?<=})",
108 | "name": "meta.at-rule.keyframes.scss",
109 | "patterns": [
110 | {
111 | "match": "(?<=@keyframes)\\s+((?:[_A-Za-z][-\\w]|-[_A-Za-z])[-\\w]*)",
112 | "captures": {
113 | "1": {
114 | "name": "entity.name.function.scss"
115 | }
116 | }
117 | },
118 | {
119 | "begin": "(?<=@keyframes)\\s+(\")",
120 | "beginCaptures": {
121 | "1": {
122 | "name": "punctuation.definition.string.begin.scss"
123 | }
124 | },
125 | "end": "\"",
126 | "endCaptures": {
127 | "0": {
128 | "name": "punctuation.definition.string.end.scss"
129 | }
130 | },
131 | "name": "string.quoted.double.scss",
132 | "contentName": "entity.name.function.scss",
133 | "patterns": [
134 | {
135 | "match": "\\\\(\\h{1,6}|.)",
136 | "name": "constant.character.escape.scss"
137 | },
138 | {
139 | "include": "source.css.scss#interpolation"
140 | }
141 | ]
142 | },
143 | {
144 | "begin": "(?<=@keyframes)\\s+(')",
145 | "beginCaptures": {
146 | "1": {
147 | "name": "punctuation.definition.string.begin.scss"
148 | }
149 | },
150 | "end": "'",
151 | "endCaptures": {
152 | "0": {
153 | "name": "punctuation.definition.string.end.scss"
154 | }
155 | },
156 | "name": "string.quoted.single.scss",
157 | "contentName": "entity.name.function.scss",
158 | "patterns": [
159 | {
160 | "match": "\\\\(\\h{1,6}|.)",
161 | "name": "constant.character.escape.scss"
162 | },
163 | {
164 | "include": "source.css.scss#interpolation"
165 | }
166 | ]
167 | },
168 | {
169 | "begin": "{",
170 | "beginCaptures": {
171 | "0": {
172 | "name": "punctuation.section.keyframes.begin.scss"
173 | }
174 | },
175 | "end": "}",
176 | "endCaptures": {
177 | "0": {
178 | "name": "punctuation.section.keyframes.end.scss"
179 | }
180 | },
181 | "patterns": [
182 | {
183 | "include": "#comments"
184 | },
185 | {
186 | "match": "\\b(?:(?:100|[1-9]\\d|\\d)%|from|to)(?=\\s*{)",
187 | "name": "entity.other.attribute-name.scss"
188 | },
189 | {
190 | "include": "#style-nesting"
191 | }
192 | ]
193 | }
194 | ]
195 | }
196 | ]
197 | },
198 | "directives": {
199 | "begin": "(@(svg|format|documentation))((\\().*\\))?",
200 | "beginCaptures": {
201 | "0": {
202 | "name": "keyword.directive.mint",
203 | "patterns": [
204 | {
205 | "match": "(?<=@svg\\()[^\\)]*",
206 | "name": "string.unquoted.mint"
207 | },
208 | {
209 | "match": "(?<=@documentation\\()[^\\)]*",
210 | "name": "entity.name.class.mint"
211 | }
212 | ]
213 | }
214 | },
215 | "end": "\\G"
216 | },
217 | "html": {
218 | "begin": "<{?",
219 | "beginCaptures": {
220 | "0": {
221 | "name": "punctuation.definition.tag.html.mint"
222 | }
223 | },
224 | "end": "}?>",
225 | "endCaptures": {
226 | "0": {
227 | "name": "punctuation.definition.tag.html.mint"
228 | }
229 | },
230 | "name": "meta.tag.html.mint",
231 | "patterns": [
232 | {
233 | "match": "(?<=<)/|/(?=>)",
234 | "name": "punctuation.definition.tag.html.mint"
235 | },
236 | {
237 | "match": "(?<=<|)[^A-Z|{][a-z]*[^\\s|:|>|/]*",
238 | "name": "entity.name.tag.block.any.html.mint"
239 | },
240 | {
241 | "match": "(?![A-Z][a-z]*)(?<=::)[^\\s|>|::|\\(|/]*",
242 | "name": "entity.name.tag.css.mint"
243 | },
244 | {
245 | "include": "#html"
246 | },
247 | {
248 | "include": "#directives"
249 | },
250 | {
251 | "include": "#regex"
252 | },
253 | {
254 | "include": "#js"
255 | },
256 | {
257 | "include": "#strings"
258 | },
259 | {
260 | "include": "#keywords"
261 | }
262 | ]
263 | },
264 | "interpolation": {
265 | "begin": "#{",
266 | "beginCaptures": {
267 | "0": {
268 | "name": "punctuation.definition.template-expression.begin.mint"
269 | }
270 | },
271 | "end": "}",
272 | "endCaptures": {
273 | "0": {
274 | "name": "punctuation.definition.template-expression.end.mint"
275 | }
276 | },
277 | "name": "meta.embedded.line.mint",
278 | "patterns": [
279 | {
280 | "name": "punctuation.accessor.mint",
281 | "match": "\\."
282 | },
283 | {
284 | "include": "#keywords"
285 | }
286 | ]
287 | },
288 | "js": {
289 | "begin": "`",
290 | "end": "`",
291 | "patterns": [
292 | {
293 | "include": "source.js"
294 | }
295 | ],
296 | "name": "meta.embedded.block.js.mint"
297 | },
298 | "keywords": {
299 | "patterns": [
300 | {
301 | "match": "(?",
314 | "name": "storage.type.function.arrow.mint"
315 | },
316 | {
317 | "match": "(?=?|<=?(?=\\s|\\d|\\w)",
362 | "name": "keyword.operator.relational.mint"
363 | },
364 | {
365 | "match": "(?",
378 | "name": "keyword.operator.pipe.mint"
379 | },
380 | {
381 | "match": "\\|(?!>)",
382 | "name": "keyword.operator.copy.mint"
383 | },
384 | {
385 | "match": "\\b(true|false)\\b",
386 | "name": "constant.language.boolean.mint"
387 | },
388 | {
389 | "match": "(?'
118 | endCaptures:
119 | '0':
120 | name: punctuation.definition.tag.html.mint
121 | name: meta.tag.html.mint
122 | patterns:
123 | - match: '(?<=<)/|/(?=>)'
124 | name: punctuation.definition.tag.html.mint
125 | - match: "(?<=<|)[^A-Z|{][a-z]*[^\\s|:|>|/]*"
126 | name: entity.name.tag.block.any.html.mint
127 | - match: "(?![A-Z][a-z]*)(?<=::)[^\\s|>|::|\\(|/]*"
128 | name: entity.name.tag.css.mint
129 | - include: '#html'
130 | - include: '#directives'
131 | - include: '#regex'
132 | - include: '#js'
133 | - include: '#strings'
134 | - include: '#keywords'
135 |
136 | interpolation:
137 | begin: '#{'
138 | beginCaptures:
139 | '0':
140 | name: punctuation.definition.template-expression.begin.mint
141 | end: '}'
142 | endCaptures:
143 | '0':
144 | name: punctuation.definition.template-expression.end.mint
145 | name: meta.embedded.line.mint
146 | patterns:
147 | - name: punctuation.accessor.mint
148 | match: "\\."
149 | - include: '#keywords'
150 |
151 | js:
152 | begin: '`'
153 | end: '`'
154 | patterns:
155 | - include: source.js
156 | name: meta.embedded.block.js.mint
157 |
158 | keywords:
159 | patterns:
160 | - match: "(?'
167 | name: storage.type.function.arrow.mint
168 | - match: "(?=?|<=?(?=\\s|\\d|\\w)"
191 | name: keyword.operator.relational.mint
192 | - match: '(?"
199 | name: keyword.operator.pipe.mint
200 | - match: "\\|(?!>)"
201 | name: keyword.operator.copy.mint
202 | - match: "\\b(true|false)\\b"
203 | name: constant.language.boolean.mint
204 | - match: "(?