mirror of
https://github.com/ilyakooo0/haskell-nova.git
synced 2024-08-17 03:00:47 +03:00
.
This commit is contained in:
commit
e9d579a1c1
1
Haskell Language Server.novaextension/.gitignore
vendored
Normal file
1
Haskell Language Server.novaextension/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.DS_Store
|
@ -0,0 +1 @@
|
||||
{"activeJourney":"2022/02/18 07:57","journeys":[{"identifier":"1645171063348_43","name":"2022/02/18 07:57","path":false,"line":false,"updatedAt":1645172096799,"children":[{"identifier":"1645171063356_35","name":"Syntaxes/Haskell.xml","path":"Syntaxes/Haskell.xml","line":false,"updatedAt":1645172096799,"comment":false,"children":[{"identifier":"1645171063356_45","name":"<collection name=\"pattern-match\">","path":"Syntaxes/Haskell.xml","line":101,"updatedAt":1645172096799,"comment":false,"children":[]}]}]}]}
|
3
Haskell Language Server.novaextension/CHANGELOG.md
Normal file
3
Haskell Language Server.novaextension/CHANGELOG.md
Normal file
@ -0,0 +1,3 @@
|
||||
## Version 1.0
|
||||
|
||||
Initial release
|
72
Haskell Language Server.novaextension/README.md
Normal file
72
Haskell Language Server.novaextension/README.md
Normal file
@ -0,0 +1,72 @@
|
||||
<!--
|
||||
👋 Hello! As Nova users browse the extensions library, a good README can help them understand what your extension does, how it works, and what setup or configuration it may require.
|
||||
|
||||
Not every extension will need every item described below. Use your best judgement when deciding which parts to keep to provide the best experience for your new users.
|
||||
|
||||
💡 Quick Tip! As you edit this README template, you can preview your changes by selecting **Extensions → Activate Project as Extension**, opening the Extension Library, and selecting "Haskell Language Server" in the sidebar.
|
||||
|
||||
Let's get started!
|
||||
-->
|
||||
|
||||
<!--
|
||||
🎈 Include a brief description of the features your extension provides. For example:
|
||||
-->
|
||||
|
||||
**Haskell Language Server** provides deep integration with **An Important Language**, including the most important feature, something that's really helpful, and _a little-known secret!_
|
||||
|
||||
<!--
|
||||
🎈 It can also be helpful to include a screenshot or GIF showing your extension in action:
|
||||
-->
|
||||
|
||||
![](https://nova.app/images/en/dark/editor.png)
|
||||
|
||||
## Requirements
|
||||
|
||||
<!--
|
||||
🎈 If your extension depends on external processes or tools that users will need to have, it's helpful to list those and provide links to their installers:
|
||||
-->
|
||||
|
||||
Haskell Language Server requires some additional tools to be installed on your Mac:
|
||||
|
||||
- [Node.js 8.2.0](https://nodejs.org) and NPM 5.2.0 or newer
|
||||
|
||||
<!--
|
||||
✨ Providing tips, tricks, or other guides for installing or configuring external dependencies can go a long way toward helping your users have a good setup experience:
|
||||
-->
|
||||
|
||||
> To install the current stable version of Node, click the "Recommended for Most Users" button to begin the download. When that completes, double-click the **.pkg** installer to begin installation.
|
||||
|
||||
## Usage
|
||||
|
||||
<!--
|
||||
🎈 If your extension provides features that are invoked manually, consider describing those options for users:
|
||||
-->
|
||||
|
||||
To run Haskell Language Server:
|
||||
|
||||
- Select the **Editor → Haskell Language Server** menu item; or
|
||||
- Open the command palette and type `Haskell Language Server`
|
||||
|
||||
<!--
|
||||
🎈 Alternatively, if your extension runs automatically (as in the case of a validator), consider showing users what they can expect to see:
|
||||
-->
|
||||
|
||||
Haskell Language Server runs any time you open a local project, automatically lints all open files, then reports errors and warnings in Nova's **Issues** sidebar and the editor gutter:
|
||||
|
||||
![](https://nova.app/images/en/dark/tools/sidebars.png)
|
||||
|
||||
### Configuration
|
||||
|
||||
<!--
|
||||
🎈 If your extension offers global- or workspace-scoped preferences, consider pointing users toward those settings. For example:
|
||||
-->
|
||||
|
||||
To configure global preferences, open **Extensions → Extension Library...** then select Haskell Language Server's **Preferences** tab.
|
||||
|
||||
You can also configure preferences on a per-project basis in **Project → Project Settings...**
|
||||
|
||||
<!--
|
||||
👋 That's it! Happy developing!
|
||||
|
||||
P.S. If you'd like, you can remove these comments before submitting your extension 😉
|
||||
-->
|
@ -0,0 +1,61 @@
|
||||
exports.getHLSConfig = () => readAllConfigs(HLSKeys);
|
||||
|
||||
// X must be an object. It is modified in place and returned.
|
||||
// The second is also an object and is merged into the left one.
|
||||
function merge(x, y) {
|
||||
for (key in y) {
|
||||
if (typeof y[key] == "object" && x[key] && typeof x[key] == "object") {
|
||||
x[key] = merge(x[key], y[key]);
|
||||
} else {
|
||||
x[key] = y[key];
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
function objectifyString(s, v) {
|
||||
let previous = v;
|
||||
for (key of s.split(".").reverse()) {
|
||||
const next = {};
|
||||
next[key] = previous;
|
||||
previous = next;
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
function readOneConfig(key) {
|
||||
return objectifyString(key, nova.workspace.config.get(key));
|
||||
}
|
||||
|
||||
function readAllConfigs(keys) {
|
||||
return keys.map(readOneConfig).reduce(merge, {});
|
||||
}
|
||||
const HLSKeys = [
|
||||
"haskell.formattingProvider",
|
||||
"haskell.checkProject",
|
||||
"haskell.maxCompletions",
|
||||
"haskell.plugin.importLens.codeActionsOn",
|
||||
"haskell.plugin.importLens.codeLensOn",
|
||||
"haskell.plugin.hlint.codeActionsOn",
|
||||
"haskell.plugin.hlint.diagnosticsOn",
|
||||
"haskell.plugin.hlint.config.flags",
|
||||
"haskell.plugin.eval.globalOn",
|
||||
"haskell.plugin.moduleName.globalOn",
|
||||
"haskell.plugin.splice.globalOn",
|
||||
"haskell.plugin.haddockComments.globalOn",
|
||||
"haskell.plugin.class.globalOn",
|
||||
"haskell.plugin.retrie.globalOn",
|
||||
"haskell.plugin.tactics.globalOn",
|
||||
"haskell.plugin.tactics.config.auto_gas",
|
||||
"haskell.plugin.tactics.config.hole_severity",
|
||||
"haskell.plugin.tactics.config.max_use_ctor_actions",
|
||||
"haskell.plugin.tactics.config.timeout_duration",
|
||||
"haskell.plugin.tactics.config.proofstate_styling",
|
||||
"haskell.plugin.pragmas.codeActionsOn",
|
||||
"haskell.plugin.pragmas.completionOn",
|
||||
"haskell.plugin.ghcide-completions.config.autoExtendOn",
|
||||
"haskell.plugin.ghcide-completions.config.snippetsOn",
|
||||
"haskell.plugin.ghcide-type-lenses.globalOn",
|
||||
"haskell.plugin.ghcide-type-lenses.config.mode",
|
||||
"haskell.plugin.refineImports.globalOn",
|
||||
];
|
158
Haskell Language Server.novaextension/Scripts/download.js
Normal file
158
Haskell Language Server.novaextension/Scripts/download.js
Normal file
@ -0,0 +1,158 @@
|
||||
const {
|
||||
sendNotification,
|
||||
sendPermanentNotification,
|
||||
} = require("notifications");
|
||||
const {
|
||||
readStream,
|
||||
getStorage,
|
||||
} = require("utils");
|
||||
|
||||
exports.getHLS = getHLS;
|
||||
|
||||
let assets = null;
|
||||
async function getHLSAssets() {
|
||||
if (!assets) {
|
||||
const response = await fetch(
|
||||
"https://api.github.com/repos/haskell/haskell-language-server/releases",
|
||||
);
|
||||
if (!response.ok) {
|
||||
console.error(response.statusText);
|
||||
return null;
|
||||
}
|
||||
const respObj = await response.json();
|
||||
const pairs = respObj[0].assets.flatMap((asset) => {
|
||||
const match = asset.name.match("haskell-language-server-macOS-(.*)\.gz");
|
||||
if (match) {
|
||||
return [
|
||||
[match[1], asset.browser_download_url],
|
||||
];
|
||||
} else if (asset.name === "haskell-language-server-wrapper-macOS.gz") {
|
||||
return [
|
||||
["wrapper", asset.browser_download_url],
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
assets = Object.fromEntries(pairs);
|
||||
}
|
||||
return assets;
|
||||
}
|
||||
async function downloadTool(name) {
|
||||
notifyToolDownloading(name);
|
||||
const storagePath = getStorageForTool(name);
|
||||
console.log("Downloading " + storagePath);
|
||||
const urls = await getHLSAssets();
|
||||
const response = await fetch(urls[name]);
|
||||
if (!response.ok) {
|
||||
console.error(response.statusText);
|
||||
return null;
|
||||
}
|
||||
const p = new Promise((resolve, _reject) => {
|
||||
const gzip = new Process("/usr/bin/gzip", {
|
||||
args: ["-d"],
|
||||
});
|
||||
response.body.pipeTo(gzip.stdin);
|
||||
const file = nova.fs.open(storagePath, "x+b");
|
||||
const outReader = gzip.stdout.getReader();
|
||||
outReader.read().then(function processChunk({
|
||||
done,
|
||||
value,
|
||||
}) {
|
||||
if (done) {
|
||||
file.close;
|
||||
console.log("Downloaded " + storagePath);
|
||||
const chmod = new Process("/bin/chmod", {
|
||||
args: ["+x", storagePath],
|
||||
});
|
||||
chmod.onDidExit((exitCode) => {
|
||||
console.log(exitCode);
|
||||
resolve(storagePath);
|
||||
});
|
||||
chmod.start();
|
||||
} else {
|
||||
file.write(value);
|
||||
outReader.read().then(processChunk);
|
||||
}
|
||||
});
|
||||
console.log("unzipping");
|
||||
gzip.start();
|
||||
});
|
||||
return await p;
|
||||
}
|
||||
async function getTool(name) {
|
||||
const path = getStorageForTool(name);
|
||||
if (nova.fs.access(path, nova.fs.X_OK)) {
|
||||
console.log("Exists: " + path);
|
||||
return path;
|
||||
} else {
|
||||
console.log("Doesn't exists: " + path);
|
||||
nova.fs.remove(path);
|
||||
return await downloadTool(name);
|
||||
}
|
||||
}
|
||||
async function getGHCVersion() {
|
||||
const wrapper = await getTool("wrapper");
|
||||
sendNotification("Woking out the GHC version of the project", "");
|
||||
const process = new Process(wrapper, {
|
||||
cwd: nova.workspace.path,
|
||||
args: ["--project-ghc-version"],
|
||||
});
|
||||
const promise = new Promise((resolve, _reject) => {
|
||||
process.onDidExit((exitCode) => {
|
||||
if (exitCode == 0) {
|
||||
readStream(process.stdout).then((x) => {
|
||||
const version = x.trim();
|
||||
sendNotification("Detected GHC " + version, "");
|
||||
resolve(version);
|
||||
});
|
||||
} else {
|
||||
readStream(process.stderr).then((x) => {
|
||||
const rRes = x.match(/Cradle requires (.+) but couldn't find it/);
|
||||
if (rRes) {
|
||||
let tool;
|
||||
switch (rRes[1]) {
|
||||
case "stack":
|
||||
tool = "Stack";
|
||||
break;
|
||||
case "cabal":
|
||||
tool = "Cabal";
|
||||
break;
|
||||
case "ghc":
|
||||
tool = "GHC";
|
||||
break;
|
||||
default:
|
||||
tool = rRes[1];
|
||||
break;
|
||||
}
|
||||
sendPermanentNotification(
|
||||
tool + " not installed!",
|
||||
"Please install " + tool +
|
||||
" and restart Haskell Language Server.",
|
||||
);
|
||||
} else {
|
||||
sendPermanentNotification("Couldn't detect GHC version", x);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
process.start();
|
||||
return promise;
|
||||
}
|
||||
async function getHLS() {
|
||||
const version = await getGHCVersion();
|
||||
return await getTool(version);
|
||||
}
|
||||
|
||||
function getStorageForTool(name) {
|
||||
return getStorage() + "/" + getToolName(name);
|
||||
}
|
||||
|
||||
function getToolName(name) {
|
||||
return "haskell-language-server-" + name;
|
||||
}
|
||||
|
||||
function notifyToolDownloading(name) {
|
||||
sendNotification("Downloading tool", "Downloading " + getToolName(name));
|
||||
}
|
143
Haskell Language Server.novaextension/Scripts/main.js
Normal file
143
Haskell Language Server.novaextension/Scripts/main.js
Normal file
@ -0,0 +1,143 @@
|
||||
const {
|
||||
sendNotification,
|
||||
sendNotificationWithAction,
|
||||
} = require("notifications");
|
||||
const {
|
||||
getHLS,
|
||||
} = require("download");
|
||||
const {
|
||||
getHLSConfig,
|
||||
} = require("configuration");
|
||||
const {
|
||||
getFileName,
|
||||
} = require("utils");
|
||||
exports.activate = function () {
|
||||
nova.commands.register("stop", (_workspace) => {
|
||||
stopServer();
|
||||
});
|
||||
nova.commands.register("restart", (_workspace) => {
|
||||
startServer();
|
||||
});
|
||||
nova.commands.register("clear-cache", (_workspace) => {
|
||||
nova.fs.rmdir(nova.extension.globalStoragePath);
|
||||
startServer();
|
||||
});
|
||||
nova.commands.register("format", formatFile);
|
||||
// startServer();
|
||||
};
|
||||
exports.deactivate = function () {
|
||||
// Clean up state before the extension is deactivated
|
||||
if (lspClient) {
|
||||
lspClient.stop();
|
||||
lspClient = null;
|
||||
}
|
||||
};
|
||||
|
||||
function formatFile(editor) {
|
||||
// If there is no URI, there's not much we can do ;(
|
||||
if (editor.document.uri) {
|
||||
const name = getFileName(editor.document.uri);
|
||||
let valid = true;
|
||||
const removeNotification = sendNotificationWithAction(
|
||||
"Formatting " + name,
|
||||
"Waiting for Haskell Language Server to format " + name,
|
||||
"Cancel",
|
||||
() => {
|
||||
valid = false;
|
||||
},
|
||||
);
|
||||
editor.onDidChange(() => {
|
||||
removeNotification();
|
||||
valid = false;
|
||||
});
|
||||
const req = {
|
||||
textDocument: {
|
||||
uri: editor.document.uri,
|
||||
},
|
||||
options: {
|
||||
tabSize: editor.tabLength,
|
||||
insertSpaces: true,
|
||||
},
|
||||
};
|
||||
lspClient.sendRequest("textDocument/formatting", req).then((edits) => {
|
||||
editor.edit((edit) => {
|
||||
if (valid) {
|
||||
const range = new Range(0, editor.document.length);
|
||||
const documentText = editor.document.getTextInRange(range);
|
||||
const newText = applyAllLSPEdits(edits, documentText);
|
||||
if (valid) {
|
||||
edit.replace(range, newText);
|
||||
}
|
||||
}
|
||||
removeNotification();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function applyAllLSPEdits(edits, text) {
|
||||
let i = 0;
|
||||
let line = 0;
|
||||
let out = "";
|
||||
|
||||
function goToLine(l) {
|
||||
while (line < l) {
|
||||
if (text.slice(i, i + 2) === "\r\n") {
|
||||
line += 1;
|
||||
i += 1;
|
||||
} else if (text[i] === "\n" || text[i] === "\r") {
|
||||
line += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
let edit;
|
||||
for (edit of edits) {
|
||||
const prev = i;
|
||||
goToLine(edit.range.start.line);
|
||||
i += edit.range.start.character;
|
||||
out += text.slice(prev, i);
|
||||
goToLine(edit.range.end.line);
|
||||
i += edit.range.end.character;
|
||||
out += edit.newText;
|
||||
console.log(out);
|
||||
}
|
||||
out += text.slice(i);
|
||||
return out;
|
||||
}
|
||||
let lspClient = null;
|
||||
async function startServer() {
|
||||
stopServer();
|
||||
const path = await getServerPath();
|
||||
const serverOptions = {
|
||||
path: path,
|
||||
args: ["lsp", "--cwd", nova.workspace.path],
|
||||
};
|
||||
const clientOptions = {
|
||||
syntaxes: ["haskell"],
|
||||
initializationOptions: getHLSConfig(),
|
||||
};
|
||||
lspClient = new LanguageClient(
|
||||
"haskell-language-server",
|
||||
nova.extension.name,
|
||||
serverOptions,
|
||||
clientOptions,
|
||||
);
|
||||
sendNotification("Starting Haskell Language Server", "");
|
||||
lspClient.start();
|
||||
}
|
||||
|
||||
function stopServer() {
|
||||
if (lspClient) {
|
||||
sendNotification("Stopping Haskell Language Server", "");
|
||||
lspClient.stop();
|
||||
lspClient = null;
|
||||
}
|
||||
}
|
||||
function getServerPath() {
|
||||
return getHLS();
|
||||
}
|
||||
|
||||
// function getLogPath() {
|
||||
// return getStorage() + "/haskell-language-server.log";
|
||||
// }
|
@ -0,0 +1,36 @@
|
||||
function sendNotification(title, body) {
|
||||
const request = new NotificationRequest();
|
||||
request.title = title;
|
||||
request.body = body;
|
||||
nova.notifications.add(request);
|
||||
}
|
||||
|
||||
function sendPermanentNotification(title, body) {
|
||||
const request = new NotificationRequest();
|
||||
request.title = title;
|
||||
request.body = body;
|
||||
request.actions = ["OK"];
|
||||
nova.notifications.add(request);
|
||||
}
|
||||
|
||||
function sendNotificationWithAction(title, body, actionName, action) {
|
||||
const now = Date.now().toString();
|
||||
const request = new NotificationRequest(now);
|
||||
request.title = title;
|
||||
request.body = body;
|
||||
request.actions = [actionName];
|
||||
nova.notifications.add(request).then((x) => {
|
||||
if (x) {
|
||||
action();
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
nova.notifications.cancel(now);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sendNotification,
|
||||
sendPermanentNotification,
|
||||
sendNotificationWithAction,
|
||||
};
|
51
Haskell Language Server.novaextension/Scripts/utils.js
Normal file
51
Haskell Language Server.novaextension/Scripts/utils.js
Normal file
@ -0,0 +1,51 @@
|
||||
function readStream(readableStream) {
|
||||
return new Promise((resolve, _reject) => {
|
||||
const reader = readableStream.getReader();
|
||||
let out = "";
|
||||
reader.read().then(function processChunk({
|
||||
done,
|
||||
value,
|
||||
}) {
|
||||
if (done) {
|
||||
resolve(out);
|
||||
} else {
|
||||
out += arrayBufferToString(value);
|
||||
reader.read().then(processChunk);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function arrayBufferToString(buffer) {
|
||||
const arr = new Uint8Array(buffer);
|
||||
const str = String.fromCharCode.apply(String, arr);
|
||||
if (/[\u0080-\uffff]/.test(str)) {
|
||||
throw new Error("this string seems to contain (still encoded) multibytes");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function getStorage() {
|
||||
try {
|
||||
nova.fs.mkdir(nova.extension.globalStoragePath);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return nova.extension.globalStoragePath;
|
||||
}
|
||||
|
||||
function getFileName(path) {
|
||||
return path.replace(/^.*[\\\/]/, "");
|
||||
}
|
||||
|
||||
function trace(x) {
|
||||
console.log(JSON.stringify(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
function traceRaw(x) {
|
||||
console.log(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { readStream, getStorage, getFileName, trace, traceRaw };
|
821
Haskell Language Server.novaextension/Syntaxes/Haskell.xml
Normal file
821
Haskell Language Server.novaextension/Syntaxes/Haskell.xml
Normal file
@ -0,0 +1,821 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<syntax name="haskell">
|
||||
<meta>
|
||||
<name>Haskell</name>
|
||||
<type>compiled</type>
|
||||
<preferred-file-extension>hs</preferred-file-extension>
|
||||
</meta>
|
||||
|
||||
<detectors>
|
||||
<extension priority="1.0">hs</extension>
|
||||
</detectors>
|
||||
|
||||
<comments>
|
||||
<single>
|
||||
<expression>--</expression>
|
||||
</single>
|
||||
<multiline>
|
||||
<starts-with>
|
||||
<expression>{-</expression>
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>-}</expression>
|
||||
</ends-with>
|
||||
</multiline>
|
||||
</comments>
|
||||
|
||||
<brackets>
|
||||
<pair open="{" close="}" />
|
||||
<pair open="[" close="]" />
|
||||
<pair open="(" close=")" />
|
||||
</brackets>
|
||||
|
||||
<surrounding-pairs>
|
||||
<pair open="[" close="]" />
|
||||
<pair open="(" close=")" />
|
||||
<pair open="'" close="'" />
|
||||
<pair open=""" close=""" />
|
||||
<pair open="`" close="`" />
|
||||
</surrounding-pairs>
|
||||
|
||||
<indentation>
|
||||
<increase>
|
||||
<expression>
|
||||
(case|class|do|let|where).*
|
||||
</expression>
|
||||
</increase>
|
||||
<decrease>
|
||||
<expression>^\\s*(end|done|with|in|else)\\b|^\\s*;;</expression>
|
||||
</decrease>
|
||||
</indentation>
|
||||
|
||||
|
||||
<scopes>
|
||||
<include syntax="self" collection="comments" />
|
||||
<include syntax="self" collection="module" />
|
||||
<include syntax="self" collection="import" />
|
||||
<include syntax="self" collection="type-family-definition" />
|
||||
<include syntax="self" collection="pattern-definition" />
|
||||
<include syntax="self" collection="type-definition" />
|
||||
<!-- <include syntax="self" collection="type-annotation" /> -->
|
||||
<include syntax="self" collection="data-definition" />
|
||||
<include syntax="self" collection="GADT-definition" />
|
||||
<include syntax="self" collection="instance" />
|
||||
<include syntax="self" collection="typeclass" />
|
||||
<include syntax="self" collection="definition" />
|
||||
</scopes>
|
||||
|
||||
<template-scopes>
|
||||
<include syntax="self" collection="Quote" />
|
||||
<include syntax="self" collection="comments" />
|
||||
</template-scopes>
|
||||
|
||||
<collections>
|
||||
|
||||
|
||||
<collection name="operators">
|
||||
<scope name="keyword.modifier">
|
||||
<expression>(!|#|\$|%|&|⋆|\+|\.|/|<|=|>|\?|@|\\|\^|\||-|~|:)+</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="expressions">
|
||||
<include syntax="self" collection="do-bind" />
|
||||
<include syntax="self" collection="literal" />
|
||||
<include syntax="self" collection="operators" />
|
||||
<include syntax="self" collection="list" />
|
||||
<include syntax="self" collection="lambda-case" />
|
||||
<include syntax="self" collection="lambda-head" />
|
||||
<include syntax="self" collection="type-applications" />
|
||||
<include syntax="self" collection="case-expression" />
|
||||
<include syntax="self" collection="qvarid" />
|
||||
<include syntax="self" collection="bind-arrow" />
|
||||
<include syntax="self" collection="tuple" />
|
||||
|
||||
|
||||
|
||||
<!-- Needed for do binds -->
|
||||
<!-- <include syntax="self" collection="pattern-match" /> -->
|
||||
</collection>
|
||||
|
||||
<collection name="pattern-match">
|
||||
<include syntax="self" collection="literal" />
|
||||
<include syntax="self" collection="view-pattern" />
|
||||
<include syntax="self" collection="tuple-match" />
|
||||
<!-- <include syntax="self" collection="at-pattern" /> -->
|
||||
<include syntax="self" collection="varid" />
|
||||
<include syntax="self" collection="qconid" />
|
||||
<include syntax="self" collection="record-match" />
|
||||
<include syntax="self" collection="list-pattern" />
|
||||
</collection>
|
||||
|
||||
<collection name="type-applications">
|
||||
<scope name="type-applications">
|
||||
<starts-with>
|
||||
<expression>(\s@)\(</expression>
|
||||
<capture number="1" name="haskell.keyword.operator.typeapplication" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>)</expression>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="type" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
<scope name="type-applications-single">
|
||||
<expression>(@)(\w+)</expression>
|
||||
<capture number="1" name="haskell.keyword.operator.typeapplication" />
|
||||
<capture number="2" name="haskell.identifier.type" />
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="Quote">
|
||||
<scope name="haskell.quasiquote.string-template">
|
||||
<starts-with>
|
||||
<expression>\[((?:\w|')+)\|</expression>
|
||||
<capture number="1" name="haskell.identifier.constant" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>\|\]</expression>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="haskell.quasiquote.string-template.value">
|
||||
<expression>.+?</expression>
|
||||
</scope>
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="record-match">
|
||||
<include syntax="self" collection="qconid" />
|
||||
<include syntax="self" collection="record-fields-match" />
|
||||
<include syntax="self" collection="record-fields-match-all" />
|
||||
</collection>
|
||||
|
||||
|
||||
<collection name="record-fields-match">
|
||||
<scope name="record-fields-match">
|
||||
<symbol type="expression" />
|
||||
<starts-with>
|
||||
<expression>(\{)</expression>
|
||||
<capture number="1" name="haskell.pattern.record.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\})</expression>
|
||||
<capture number="1" name="haskell.pattern.record.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="pattern-match" />
|
||||
<include syntax="self" collection="varid" />
|
||||
<scope name="record-sep">
|
||||
<expression>=</expression>
|
||||
</scope>
|
||||
<scope name="record-sep">
|
||||
<expression>,</expression>
|
||||
</scope>
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="record-fields-match-wildcard">
|
||||
<scope name="record-fields-match-all">
|
||||
<starts-with>
|
||||
<expression>(\{)</expression>
|
||||
<capture number="1" name="haskell.pattern.record.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\})</expression>
|
||||
<capture number="1" name="haskell.pattern.record.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="haskell.pattern.record.wildcard">
|
||||
<expression>\.\.</expression>
|
||||
</scope>
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="bind-arrow">
|
||||
<scope name="haskell.operator.bind-arrow">
|
||||
<expression><-</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
|
||||
<collection name="list">
|
||||
<symbol type="expression" />
|
||||
<scope name="haskell.list">
|
||||
<starts-with>
|
||||
<expression>(\[)</expression>
|
||||
<capture number="1" name="haskell.list.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\])</expression>
|
||||
<capture number="1" name="haskell.list.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="expressions" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="list-pattern">
|
||||
<symbol type="expression" />
|
||||
<scope name="haskell.pattern.list">
|
||||
<starts-with>
|
||||
<expression>(\[)</expression>
|
||||
<capture number="1" name="haskell.pattern.list.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\])</expression>
|
||||
<capture number="1" name="haskell.pattern.list.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="pattern-match" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
|
||||
<collection name="view-pattern">
|
||||
<scope name="haskell.pattern.view">
|
||||
<symbol type="expression" />
|
||||
<starts-with>
|
||||
<expression>(\()</expression>
|
||||
<capture number="1" name="haskell.pattern.view.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\))</expression>
|
||||
<capture number="1" name="haskell.pattern.view.bracket" />
|
||||
</ends-with>
|
||||
<subscopes anchored="true">
|
||||
<include syntax="self" collection="expressions" />
|
||||
<scope name="haskell.pattern.view.operator.arrow">
|
||||
<expression>-></expression>
|
||||
</scope>
|
||||
<include syntax="self" collection="pattern-match" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="tuple-match">
|
||||
<symbol type="expression" />
|
||||
<scope name="haskell.pattern.tuple">
|
||||
<starts-with>
|
||||
<expression>(\()</expression>
|
||||
<capture number="1" name="haskell.pattern.tuple.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\))</expression>
|
||||
<capture number="1" name="haskell.pattern.tuple.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="pattern-match" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="case-expression">
|
||||
<scope name="haskell.case">
|
||||
<starts-with>
|
||||
<expression>(case)</expression>
|
||||
<capture number="1" name="haskell.case.keyword.condition" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(of)</expression>
|
||||
<capture number="1" name="haskell.case.keyword.condition" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="expressions" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="tuple">
|
||||
<symbol type="expression" />
|
||||
<scope name="haskell.tuple">
|
||||
<starts-with>
|
||||
<expression>(\()</expression>
|
||||
<capture number="1" name="haskell.tuple.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\))</expression>
|
||||
<capture number="1" name="haskell.tuple.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="expressions" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="typeclass">
|
||||
<symbol type="interface" />
|
||||
<scope name="haskell.definition.class">
|
||||
<starts-with>
|
||||
<expression>^(\h*)(class)($|\h)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.class" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="haskell.keyword.construct.where">
|
||||
<expression>where</expression>
|
||||
</scope>
|
||||
<include syntax="self" collection="type" />
|
||||
<include syntax="self" collection="type-definition" />
|
||||
<!-- <include syntax="self" collection="type-annotation" /> -->
|
||||
<include syntax="self" collection="definition" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="instance">
|
||||
<scope name="haskell.instance">
|
||||
<symbol type="category" />
|
||||
<starts-with>
|
||||
<expression>^(\h*)(instance)($|\h)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.instance" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="haskell.keyword.construct.where">
|
||||
<expression>where</expression>
|
||||
</scope>
|
||||
<include syntax="self" collection="type" />
|
||||
<include syntax="self" collection="type-definition" />
|
||||
<include syntax="self" collection="type-annotation" />
|
||||
<include syntax="self" collection="definition" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="type-family-definition">
|
||||
<scope name="haskell.definition.type.type-family">
|
||||
<symbol type="type" />
|
||||
<starts-with>
|
||||
<expression>^(\h*)(type\h+family)\h+`?(\w(\w|')*)`?($|\h)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.type-family" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="haskell.keyword.construct.where">
|
||||
<expression>where</expression>
|
||||
</scope>
|
||||
<include syntax="self" collection="type" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="definition">
|
||||
<scope name="haskell.definition.type.function">
|
||||
<symbol type="function">
|
||||
<display-name>
|
||||
<component selector="haskell.definition.type.function" />
|
||||
</display-name>
|
||||
|
||||
</symbol>
|
||||
<starts-with>
|
||||
<expression>^(?=(\h*)(default\h+)?`?(\w(\w|')*)`?($|\h))</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.default" />
|
||||
<capture number="3" name="haskell.identifier.function" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\1\3\s)(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="type-annotation" />
|
||||
<include syntax="self" collection="implementation" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="do-bind">
|
||||
<scope name="do-bind">
|
||||
<starts-with>
|
||||
<expression>^(?=(\h*).+<-($|\h))</expression>
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\0)(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes anchored="true">
|
||||
<include syntax="self" collection="pattern-match" />
|
||||
<scope name="bind-arrow">
|
||||
<expression><-</expression>
|
||||
</scope>
|
||||
<include syntax="self" collection="expressions" repeat="true" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="implementation">
|
||||
<scope name="haskell.definition.type.function">
|
||||
<local scope="within-construct" />
|
||||
<starts-with>
|
||||
<expression>^(\h*)(default\h+)?`?(\w(\w|')*)`?($|\h)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.default" />
|
||||
<capture number="3" name="haskell.identifier.function" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\1\3\s)(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="where-clause" />
|
||||
<include syntax="self" collection="expressions" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="type-annotation">
|
||||
<scope name="haskell.definition.type.function">
|
||||
<starts-with>
|
||||
<expression>^(\h*)`?(\w(\w|')*)`?\h*::($|\h)</expression>
|
||||
<capture number="2" name="haskell.identifier.function" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="type" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="type-definition">
|
||||
<scope name="haskell.definition.type">
|
||||
<starts-with>
|
||||
<expression>^(\h*)(type)\h+(\w(\w|')*)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.type" />
|
||||
<capture number="3" name="haskell.identifier.type" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="type" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="GADT-definition">
|
||||
<scope name="haskell.definition.struct.GADT">
|
||||
<starts-with>
|
||||
<expression>^(\h*)(data)\h+(\w(\w|')*)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.data.GADT" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="gadt-constructor" />
|
||||
<include syntax="self" collection="type" />
|
||||
<include syntax="self" collection="record-definition" />
|
||||
<include syntax="self" collection="record-definition-field-name" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="gadt-constructor">
|
||||
<scope name="identifier.type.struct.GADT.constructor">
|
||||
<expression>^\h+[A-Z](\w|')*</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="data-definition">
|
||||
<scope name="haskell.definition.struct.data">
|
||||
<starts-with>
|
||||
<expression>^(\h*)(data|newtype)\h+(\w(\w|')*)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.data.newtype" />
|
||||
<capture number="3" name="haskell.identifier.type" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="record-definition" />
|
||||
<include syntax="self" collection="data-constructor" />
|
||||
<include syntax="self" collection="type" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="data-constructor">
|
||||
<scope name="haskell.identifier.type.struct.data.constructor">
|
||||
<expression>=\h+[A-Z](\w|')*</expression>
|
||||
</scope>
|
||||
<scope name="haskell.identifier.type.struct.data.constructor">
|
||||
<expression>\|\h+[A-Z](\w|')*</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="record-definition">
|
||||
<scope name="haskell.record">
|
||||
<starts-with>
|
||||
<expression>(\{)</expression>
|
||||
<capture number="1" name="haskell.record.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\})</expression>
|
||||
<capture number="1" name="haskell.record.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="record-definition-field-name" />
|
||||
<include syntax="self" collection="type" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="record-definition-field-name">
|
||||
<scope name="haskell.record.definition.property">
|
||||
<expression>\w(\w|')*\h*::</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="type">
|
||||
<include syntax="self" collection="type-list" />
|
||||
<scope name="haskell.identifier.type">
|
||||
<expression>([A-Z](\w|')*\.)*[A-Z](\w|')*</expression>
|
||||
</scope>
|
||||
<scope name="haskell.keyword.construct.forall">
|
||||
<expression>forall</expression>
|
||||
</scope>
|
||||
<scope name="haskell.identifier.type.variable">
|
||||
<expression>\w(\w|')*</expression>
|
||||
</scope>
|
||||
<scope name="haskell.keyword.construct.function-arrow">
|
||||
<expression>-></expression>
|
||||
</scope>
|
||||
<scope name="haskell.keyword.construct.fat-arrow">
|
||||
<expression>=></expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="pattern-definition">
|
||||
<scope name="haskell.pattern">
|
||||
<starts-with>
|
||||
<expression>^(\h*)(pattern)\h+(\w(\w|')*)</expression>
|
||||
<capture number="2" name="haskell.keyword.construct.pattern" />
|
||||
<capture number="3" name="haskell.identifier.decorator.pattern" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\s+\1\S)(?!\s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="haskell.keyword.construct.where">
|
||||
<expression>where</expression>
|
||||
</scope>
|
||||
<include syntax="self" collection="expressions" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="type-list">
|
||||
<scope name="haskell.type-list">
|
||||
<starts-with>
|
||||
<expression>('\[)</expression>
|
||||
<capture number="1" name="haskell.type-list.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\])</expression>
|
||||
<capture number="1" name="haskell.type-list.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="type" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="lambda-head">
|
||||
<scope name="haskell.lambda">
|
||||
<starts-with>
|
||||
<expression>(\\)</expression>
|
||||
<capture number="1" name="haskell.keyword.construct.lambda" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(->)</expression>
|
||||
<capture number="1" name="haskell.keyword.construct.lambda" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="pattern-match" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="lambda-case">
|
||||
<scope name="haskell.keyword.condition.lambda-case">
|
||||
<expression>\\case</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="where-clause">
|
||||
<scope name="haskell.construct.where">
|
||||
<local scope="within-parent" />
|
||||
<starts-with>
|
||||
<expression>^(\h*)(where)</expression>
|
||||
<capture number="2" name="haskell.construct.keyword.where" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<template>^(?!\1\s*\S)(?!s*$)</template>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<include syntax="self" collection="definition" />
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
|
||||
<collection name="qvarid">
|
||||
<scope name="haskell.identifier.function">
|
||||
<expression>([A-Z](\w|')*\.)*\w(\w|')*</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="varid">
|
||||
<scope name="haskell.identifier.variable">
|
||||
<expression>\w(\w|')*</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="qconid">
|
||||
<scope name="haskell.identifier.type.struct.constructor">
|
||||
<expression>([A-Z](\w|')*\.)*[A-Z](\w|')*</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="qconsym">
|
||||
<scope name="haskell.identifier.decorator.pattern">
|
||||
<expression>([A-Z](\w|')*\.):(\w|')*</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="literal">
|
||||
<include syntax="self" collection="number" />
|
||||
<include syntax="self" collection="strings" />
|
||||
</collection>
|
||||
|
||||
|
||||
<collection name="strings">
|
||||
<scope name="haskell.string.double-quoted">
|
||||
<starts-with>
|
||||
<expression>"</expression>
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>"</expression>
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="haskell.string.escape-sequences">
|
||||
<expression>\\.</expression>
|
||||
</scope>
|
||||
</subscopes>
|
||||
</scope>
|
||||
<scope name="haskell.string.single-quoted">
|
||||
<expression>'([^'\\]|\\.)'</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
|
||||
<collection name="number">
|
||||
<scope name="haskell.value.number">
|
||||
<expression>(0x|0o|0O|0X)?\d+(\d|_)*(\.[\d|_]+)?((e|E)(\+|-)?\d+)?</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
|
||||
<collection name="module">
|
||||
<scope name="haskell.definition.module.package">
|
||||
<starts-with>
|
||||
<expression>^(module)\s+(\w|\.)+</expression>
|
||||
<capture number="1" name="haskell.construct.keyword.module" />
|
||||
<capture number="2" name="haskell.definition.module.package" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(where)</expression>
|
||||
<capture number="1" name="haskell.construct.keyword.module" />
|
||||
</ends-with>
|
||||
<subscopes export-symbols="true">
|
||||
<scope name="identifier.constant">
|
||||
<expression>(\w|')+</expression>
|
||||
</scope>
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="import">
|
||||
<scope name="haskell.construct.keyword.import">
|
||||
<expression>^import\s</expression>
|
||||
</scope>
|
||||
<scope name="haskell.construct.keyword.qualified">
|
||||
<expression>qualified</expression>
|
||||
</scope>
|
||||
<scope name="haskell.construct.keyword.as">
|
||||
<expression>as</expression>
|
||||
</scope>
|
||||
<scope name="haskell.identifier.module.package">
|
||||
<expression>([A-Z](\w|')*\.)*[A-Z](\w|')*</expression>
|
||||
</scope>
|
||||
<include syntax="self" collection="import-list" />
|
||||
</collection>
|
||||
|
||||
<collection name="import-list">
|
||||
<scope name="import-list">
|
||||
<starts-with>
|
||||
<expression>(\()</expression>
|
||||
<capture number="1" name="haskell.import-list.bracket" />
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>(\))</expression>
|
||||
<capture number="1" name="haskell.import-list.bracket" />
|
||||
</ends-with>
|
||||
<subscopes>
|
||||
<scope name="identifier.decorator">
|
||||
<expression>([A-Z](\w|')*\.)*\w(\w|')*</expression>
|
||||
</scope>
|
||||
</subscopes>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<!-- <collection name="special">
|
||||
<scope>
|
||||
<expression>(;|,)</expression>
|
||||
</scope>
|
||||
</collection> -->
|
||||
|
||||
|
||||
<collection name="reservedop">
|
||||
<scope name="keyword.operator">
|
||||
<expression>(\.\.|:|::|=|\\|\||<-|->|@|~|=>)</expression>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="keywords">
|
||||
<scope name="haskell.keyword.modifier">
|
||||
<symbol type="keyword" />
|
||||
<strings>
|
||||
<string>do</string>
|
||||
<string>in</string>
|
||||
<string>infix</string>
|
||||
<string>infixl</string>
|
||||
<string>infixr</string>
|
||||
<string>where</string>
|
||||
<string>let</string>
|
||||
</strings>
|
||||
</scope>
|
||||
<scope name="haskell.keyword.condition">
|
||||
<symbol type="keyword" />
|
||||
<strings>
|
||||
<string>of</string>
|
||||
<string>case</string>
|
||||
<string>else</string>
|
||||
<string>if</string>
|
||||
<string>then</string>
|
||||
</strings>
|
||||
</scope>
|
||||
<scope name="haskell.keyword.keyword.construct">
|
||||
<symbol type="keyword" />
|
||||
<strings>
|
||||
<string>instance</string>
|
||||
<string>newtype</string>
|
||||
<string>module</string>
|
||||
<string>type</string>
|
||||
<string>class</string>
|
||||
<string>data</string>
|
||||
<string>default</string>
|
||||
<string>deriving</string>
|
||||
<string>foreign</string>
|
||||
</strings>
|
||||
</scope>
|
||||
<scope name="haskell.keyword.self">
|
||||
<symbol type="keyword" />
|
||||
<strings>
|
||||
<string>undefined</string>
|
||||
<string>_</string>
|
||||
</strings>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
<collection name="comments">
|
||||
<scope name="haskell.comment.single" spell-check="true">
|
||||
<starts-with>
|
||||
<expression>--</expression>
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>$</expression>
|
||||
</ends-with>
|
||||
</scope>
|
||||
<scope name="haskell.comment.block" spell-check="true">
|
||||
<starts-with>
|
||||
<expression>{-</expression>
|
||||
</starts-with>
|
||||
<ends-with>
|
||||
<expression>-}</expression>
|
||||
</ends-with>
|
||||
</scope>
|
||||
</collection>
|
||||
|
||||
|
||||
</collections>
|
||||
</syntax>
|
300
Haskell Language Server.novaextension/extension.json
Normal file
300
Haskell Language Server.novaextension/extension.json
Normal file
@ -0,0 +1,300 @@
|
||||
{
|
||||
"identifier": "iko.soy.HaskellLanguageServer",
|
||||
"name": "Haskell Language Server",
|
||||
"organization": "iko",
|
||||
"description": "Lorem ipsum, dolor sit amet.",
|
||||
"version": "1.0",
|
||||
"categories": ["languages", "formatters"],
|
||||
"main": "main.js",
|
||||
"entitlements": {
|
||||
"process": true,
|
||||
"filesystem": "readwrite",
|
||||
"requests": true
|
||||
},
|
||||
"configWorkspace": [{
|
||||
"key": "haskell-language-server-path",
|
||||
"title": "Haskell Language Server path",
|
||||
"description": "If you want to use a custom HLS build for this project, then specify the path to it here.",
|
||||
"type": "path",
|
||||
"placeholder": "/usr/local/bin/example"
|
||||
}, {
|
||||
"type": "section",
|
||||
"title": "Haskell Language Server settings",
|
||||
"children": [{
|
||||
"key": "haskell.formattingProvider",
|
||||
"title": "Code formatter",
|
||||
"type": "enum",
|
||||
"values": [
|
||||
"brittany",
|
||||
"floskell",
|
||||
"fourmolu",
|
||||
"ormolu",
|
||||
"stylish-haskell",
|
||||
"none"
|
||||
],
|
||||
"default": "ormolu",
|
||||
"description": "The formatter to use when formatting a document or range. Ensure the plugin is enabled."
|
||||
}, {
|
||||
"key": "haskell.checkProject",
|
||||
"title": "Check whole project",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether to typecheck the entire project on load. It could drive to bad perfomance in large projects."
|
||||
}, {
|
||||
"key": "haskell.maxCompletions",
|
||||
"type": "number",
|
||||
"title": "Maximum number of completions",
|
||||
"description": "Maximum number of completions sent to the editor.",
|
||||
"default": 40
|
||||
}, {
|
||||
"type": "section",
|
||||
"title": "Plugin settings",
|
||||
"children": [{
|
||||
"type": "section",
|
||||
"title": "Import lens",
|
||||
"description": "Not currently implemented in Nova",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.importLens.codeActionsOn",
|
||||
"title": "Enable code actions",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables explicit imports code actions"
|
||||
}, {
|
||||
"key": "haskell.plugin.importLens.codeLensOn",
|
||||
"title": "Enable code lens",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables explicit imports code lenses"
|
||||
}]
|
||||
}, {
|
||||
"title": "HLint",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.hlint.codeActionsOn",
|
||||
"title": "Enable code actions",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables hlint code actions (apply hints)"
|
||||
}, {
|
||||
"key": "haskell.plugin.hlint.diagnosticsOn",
|
||||
"title": "Enable diagnostics",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables hlint diagnostics"
|
||||
}, {
|
||||
"title": "Configuration",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.hlint.config.flags",
|
||||
"title": "Flags",
|
||||
"description": "Flags used by hlint",
|
||||
"default": [],
|
||||
"type": "stringArray"
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
"title": "Eval",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.eval.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables eval plugin"
|
||||
}]
|
||||
}, {
|
||||
"title": "Module name",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.moduleName.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables module name plugin"
|
||||
}]
|
||||
}, {
|
||||
"title": "Splice",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.splice.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables splice plugin (expand template haskell definitions)"
|
||||
}]
|
||||
}, {
|
||||
"title": "Haddock comments",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.haddockComments.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables haddock comments plugin"
|
||||
}]
|
||||
}, {
|
||||
"title": "Class",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.class.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables type class plugin"
|
||||
}]
|
||||
}, {
|
||||
"title": "Retrie",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.retrie.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables retrie plugin"
|
||||
}]
|
||||
}, {
|
||||
"title": "Wingman",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.tactics.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables Wingman (tactics) plugin"
|
||||
}, {
|
||||
"title": "Configuration",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.tactics.config.auto_gas",
|
||||
"title": "Gas",
|
||||
"description": "The depth of the search tree when performing \"Attempt to fill hole\". Bigger values will be able to derive more solutions, but will take exponentially more time.",
|
||||
"default": 4,
|
||||
"type": "number"
|
||||
}, {
|
||||
"key": "haskell.plugin.tactics.config.hole_severity",
|
||||
"title": "Hole severity",
|
||||
"description": "The severity to use when showing hole diagnostics.",
|
||||
"values": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
null
|
||||
],
|
||||
"default": null,
|
||||
"type": "enum"
|
||||
}, {
|
||||
"key": "haskell.plugin.tactics.config.max_use_ctor_actions",
|
||||
"title": "Max number of constructors",
|
||||
"type": "number",
|
||||
"default": 5,
|
||||
"description": "Maximum number of `Use constructor <x>` code actions that can appear"
|
||||
}, {
|
||||
"key": "haskell.plugin.tactics.config.timeout_duration",
|
||||
"title": "Timeout",
|
||||
"description": "The timeout for Wingman actions, in seconds",
|
||||
"default": 2,
|
||||
"type": "number"
|
||||
}, {
|
||||
"key": "haskell.plugin.tactics.config.proofstate_styling",
|
||||
"title": "Proof states",
|
||||
"description": "Should Wingman emit styling markup when showing metaprogram proof states?",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
"title": "Pragmas",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.pragmas.codeActionsOn",
|
||||
"title": "Enable code actions",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables pragmas code actions"
|
||||
}, {
|
||||
"key": "haskell.plugin.pragmas.completionOn",
|
||||
"title": "Enable completions",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables pragmas completions"
|
||||
}]
|
||||
}, {
|
||||
"title": "Completions",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"title": "Configuration",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.ghcide-completions.config.autoExtendOn",
|
||||
"title": "Extend with out-of-scope identifiers",
|
||||
"description": "Extends the import list automatically when completing a out-of-scope identifier",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
}, {
|
||||
"key": "haskell.plugin.ghcide-completions.config.snippetsOn",
|
||||
"title": "Insert snippets",
|
||||
"description": "Inserts snippets when using code completions",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
"description": "Not currently implemented in Nova",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.ghcide-type-lenses.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables type lenses plugin"
|
||||
}, {
|
||||
"title": "Configuration",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.ghcide-type-lenses.config.mode",
|
||||
"title": "Mode",
|
||||
"type": "enum",
|
||||
"default": true,
|
||||
"description": "Control how type lenses are shown",
|
||||
"values": ["always", "exported", "diagnostics"]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
"title": "Refine imports",
|
||||
"type": "section",
|
||||
"children": [{
|
||||
"key": "haskell.plugin.refineImports.globalOn",
|
||||
"title": "Enable",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables refine imports plugin"
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
"activationEvents": ["onLanguage:haskell", "onLanguage:hs"],
|
||||
"commands": {
|
||||
"editor": [{
|
||||
"title": "Format file with Haskell Language Server",
|
||||
"command": "format",
|
||||
"when": "editorSyntax == 'haskell' && editorHasFocus",
|
||||
"filters": {
|
||||
"syntaxes": ["haskell"]
|
||||
}
|
||||
}],
|
||||
"extensions": [{
|
||||
"title": "Stop",
|
||||
"paletteTitle": "Stop Haskell Language Server",
|
||||
"command": "stop"
|
||||
}, {
|
||||
"title": "Restart",
|
||||
"paletteTitle": "Restart Haskell Language Server",
|
||||
"command": "restart"
|
||||
}, {
|
||||
"title": "Clear cached versions",
|
||||
"paletteTitle": "Clear cached versions of Haskell Language Server",
|
||||
"command": "clear-cache"
|
||||
}]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user