Skip to content

Add option to enable/disable .cabal file support #1223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,22 @@
"Prefer a multiple component session, if the build tool supports it. At the moment, only `cabal` supports multiple components session loading. If the `cabal` version does not support loading multiple components at once, we gracefully fall back to \"singleComponent\" mode."
]
},
"haskell.supportCabalFiles": {
"scope": "resource",
"default": "automatic",
"type": "string",
"enum": [
"enable",
"disable",
"automatic"
],
"description": "Enable Language Server support for `.cabal` files. Requires Haskell Language Server version >= 1.9.0.0.",
"enumDescriptions": [
"Enable Language Server support for `.cabal` files",
"Disable Language Server support for `.cabal` files",
"Enable Language Server support for `.cabal` files if the HLS version supports it."
]
},
"haskell.maxCompletions": {
"scope": "resource",
"default": 40,
Expand Down
50 changes: 43 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import {
import { RestartServerCommandName, StartServerCommandName, StopServerCommandName } from './commands/constants';
import * as DocsBrowser from './docsBrowser';
import { HlsError, MissingToolError, NoMatchingHls } from './errors';
import { findHaskellLanguageServer, IEnvVars } from './hlsBinaries';
import { addPathToProcessPath, expandHomeDir, ExtensionLogger } from './utils';
import { callAsync, findHaskellLanguageServer, IEnvVars } from './hlsBinaries';
import { addPathToProcessPath, comparePVP, expandHomeDir, ExtensionLogger } from './utils';

// The current map of documents & folders to language servers.
// It may be null to indicate that we are in the process of launching a server,
Expand Down Expand Up @@ -205,6 +205,12 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold
args = args.concat(extraArgs.split(' '));
}

const cabalFileSupport: 'automatic' | 'enable' | 'disable' = workspace.getConfiguration(
'haskell',
uri,
).supportCabalFiles;
logger.info(`Support for '.cabal' files: ${cabalFileSupport}`);

// If we're operating on a standalone file (i.e. not in a folder) then we need
// to launch the server in a reasonable current directory. Otherwise the cradle
// guessing logic in hie-bios will be wrong!
Expand Down Expand Up @@ -253,14 +259,44 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold

const pat = folder ? `${folder.uri.fsPath}/**/*` : '**/*';
logger.log(`document selector patten: ${pat}`);

const cabalDocumentSelector = { scheme: 'file', language: 'cabal', pattern: pat };
const haskellDocumentSelector = [
{ scheme: 'file', language: 'haskell', pattern: pat },
{ scheme: 'file', language: 'literate haskell', pattern: pat },
];

const documentSelector = [...haskellDocumentSelector];

switch (cabalFileSupport) {
case 'automatic':
const hlsVersion = await callAsync(
serverExecutable,
['--numeric-version'],
logger,
currentWorkingDir,
undefined /* this command is very fast, don't show anything */,
false,
serverEnvironment,
);
if (comparePVP(hlsVersion, '1.9.0.0') >= 0) {
// If hlsVersion is >= '1.9.0.0'
documentSelector.push(cabalDocumentSelector);
}
break;
case 'enable':
documentSelector.push(cabalDocumentSelector);
break;
case 'disable':
break;
default:
break;
}

const clientOptions: LanguageClientOptions = {
// Use the document selector to only notify the LSP on files inside the folder
// path for the specific workspace.
documentSelector: [
{ scheme: 'file', language: 'haskell', pattern: pat },
{ scheme: 'file', language: 'literate haskell', pattern: pat },
{ scheme: 'file', language: 'cabal', pattern: pat },
],
documentSelector: [...documentSelector],
synchronize: {
// Synchronize the setting section 'haskell' to the server.
configurationSection: 'haskell',
Expand Down
2 changes: 1 addition & 1 deletion src/hlsBinaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type ProcessCallback = (
* @param callback Upon process termination, execute this callback. If given, must resolve promise. On error, stderr and stdout are logged regardless of whether the callback has been specified.
* @returns Stdout of the process invocation, trimmed off newlines, or whatever the `callback` resolved to.
*/
async function callAsync(
export async function callAsync(
binary: string,
args: string[],
logger: Logger,
Expand Down