Skip to content

Commit 59e01bb

Browse files
committed
Merge branch dev into published
2 parents b32f4d8 + 21c851c commit 59e01bb

10 files changed

Lines changed: 477 additions & 19 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ Changes to Calva.
44

55
## [Unreleased]
66

7+
## [2.0.539] - 2025-10-28
8+
9+
- [Use latest version of libs for Jack-in, if no specific version was set by the user](https://github.com/BetterThanTomorrow/calva/issues/2959)
10+
11+
Previous default versions:
12+
- `nrepl`: 1.3.1
13+
- `cider-nrepl`: 0.55.4
14+
- `cider/piggieback`: 0.6.0
15+
716
## [2.0.538] - 2025-10-19
817

918
- Fix: [Semantic tokens fail on some input with ignored forms](https://github.com/BetterThanTomorrow/calva/issues/2956)

docs/site/customizing-jack-in-and-connect.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ It may be helpful to view the messages sent between nREPL and Calva when trouble
171171

172172
The versions used are configurable via the VS Code settings `calva.jackInDependencyVersions`.
173173

174+
!!! Note "Latest versions by default"
175+
By default, Calva resolves the latest available versions of `nrepl`, `cider-nrepl`, and `cider/piggieback` when Jacking in. If the latest version cannot be determined, Calva falls back to the default versions pinned in Calva's `package.json`. If you specify versions in `calva.jackInDependencyVersions`, those versions take precedence and will be used. You can specify just one; any unspecified dependencies still use the latest-or-fallback behavior.
176+
174177
!!! Note "Java 1.8 compatible versions"
175178
The default dependency versions are not compatible with Java 1.8. If your project needs that version of Java you can use these settings in your Workspace `.vscode/settings.json`:
176179

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Calva: Clojure & ClojureScript Interactive Programming",
44
"description": "Integrated REPL, formatter, Paredit, and more. Powered by cider-nrepl and clojure-lsp.",
55
"icon": "assets/calva.png",
6-
"version": "2.0.538",
6+
"version": "2.0.539",
77
"publisher": "betterthantomorrow",
88
"author": {
99
"name": "Better Than Tomorrow",
@@ -475,7 +475,7 @@
475475
},
476476
"calva.jackInDependencyVersions": {
477477
"type": "object",
478-
"description": "Versions of the dependencies injected by Calva Jack-in",
478+
"description": "By default Calva Jack-in will inject the latest `nrepl`, etcetera versions when starting the repl. Override this default behaviour by declaring which versions to use here.",
479479
"properties": {
480480
"nrepl": {
481481
"type": "string",
@@ -491,9 +491,9 @@
491491
}
492492
},
493493
"default": {
494-
"nrepl": "1.3.1",
495-
"cider-nrepl": "0.55.4",
496-
"cider/piggieback": "0.6.0"
494+
"nrepl": "1.5.1",
495+
"cider-nrepl": "0.58.0",
496+
"cider/piggieback": "0.6.1"
497497
}
498498
},
499499
"calva.clojureLspVersion": {

src/config.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { isDefined } from './utilities';
1313
import * as converters from './converters';
1414
import * as nreplUtil from './nrepl/util';
1515
import * as output from './results-output/output';
16+
import { getEffectiveJackInDependencyVersions } from './nrepl/jack-in-dependency-versions';
1617

1718
const REPL_FILE_EXT = 'calva-repl';
1819
const FIDDLE_FILE_EXT = 'fiddle';
@@ -203,9 +204,7 @@ function getConfig() {
203204
testOnSave: configOptions.get('testOnSave'),
204205
showDocstringInParameterHelp: configOptions.get<boolean>('showDocstringInParameterHelp'),
205206
jackInEnv: configOptions.get('jackInEnv'),
206-
jackInDependencyVersions: configOptions.get<{
207-
JackInDependency: string;
208-
}>('jackInDependencyVersions'),
207+
jackInDependencyVersions: getEffectiveJackInDependencyVersions(),
209208
clojureLspVersion: configOptions.get<string>('clojureLspVersion'),
210209
clojureLspPath: configOptions.get<string>('clojureLspPath'),
211210
openBrowserWhenFigwheelStarted: configOptions.get<boolean>('openBrowserWhenFigwheelStarted'),
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import * as assert from 'assert';
2+
import { before, after, suite, test } from 'mocha';
3+
import * as vscode from 'vscode';
4+
import * as state from '../../../state';
5+
import {
6+
getEffectiveJackInDependencyVersions,
7+
JackInDependencyKey,
8+
refreshJackInDependencyVersions,
9+
} from '../../../nrepl/jack-in-dependency-versions';
10+
11+
const SUITE = 'Jack-in dependency versions';
12+
const GLOBAL_STATE_KEY = 'calva.jackIn.latestDependencyVersions';
13+
14+
type Versions = Partial<Record<JackInDependencyKey, string>>;
15+
16+
let prevWorkspaceValue: Versions | undefined;
17+
let prevStoredValue: Versions | undefined;
18+
19+
suite(SUITE, () => {
20+
before(async () => {
21+
const ext = vscode.extensions.getExtension('betterthantomorrow.calva');
22+
await ext?.activate();
23+
24+
await refreshJackInDependencyVersions();
25+
26+
const inspected = vscode.workspace
27+
.getConfiguration('calva')
28+
.inspect<Versions>('jackInDependencyVersions');
29+
prevWorkspaceValue = inspected?.workspaceValue;
30+
31+
prevStoredValue = state.extensionContext?.globalState.get<Versions>(GLOBAL_STATE_KEY);
32+
});
33+
34+
after(async () => {
35+
await vscode.workspace
36+
.getConfiguration('calva')
37+
.update('jackInDependencyVersions', prevWorkspaceValue, vscode.ConfigurationTarget.Workspace);
38+
39+
await state.extensionContext?.globalState.update(GLOBAL_STATE_KEY, prevStoredValue);
40+
});
41+
42+
test('happy path: uses configured versions when set at workspace level', async () => {
43+
const configured: Record<JackInDependencyKey, string> = {
44+
nrepl: 'TEST-NREPL-1',
45+
'cider-nrepl': 'TEST-CIDER-NREPL-2',
46+
'cider/piggieback': 'TEST-PIGGIEBACK-3',
47+
};
48+
49+
await vscode.workspace
50+
.getConfiguration('calva')
51+
.update('jackInDependencyVersions', configured, vscode.ConfigurationTarget.Workspace);
52+
53+
const effective = getEffectiveJackInDependencyVersions();
54+
55+
assert.deepStrictEqual(
56+
effective,
57+
configured,
58+
`Expected configured versions to be used. Got ${JSON.stringify(effective)}`
59+
);
60+
});
61+
62+
test('partial configuration: missing keys fall back while set keys are respected', async () => {
63+
// Clear stored values to avoid influencing this test
64+
await state.extensionContext?.globalState.update(GLOBAL_STATE_KEY, {});
65+
66+
const inspectedDefaults = vscode.workspace
67+
.getConfiguration('calva')
68+
.inspect<Record<JackInDependencyKey, string>>('jackInDependencyVersions');
69+
const defaults = (inspectedDefaults?.defaultValue ?? {}) as Record<JackInDependencyKey, string>;
70+
71+
const configured: Versions = {
72+
nrepl: 'PARTIAL-NREPL-1',
73+
};
74+
75+
await vscode.workspace
76+
.getConfiguration('calva')
77+
.update('jackInDependencyVersions', configured, vscode.ConfigurationTarget.Workspace);
78+
79+
const effective = getEffectiveJackInDependencyVersions();
80+
81+
assert.strictEqual(effective.nrepl, 'PARTIAL-NREPL-1', 'nrepl should use configured value');
82+
assert.strictEqual(
83+
effective['cider-nrepl'],
84+
defaults['cider-nrepl'],
85+
'cider-nrepl should fall back to default'
86+
);
87+
assert.strictEqual(
88+
effective['cider/piggieback'],
89+
defaults['cider/piggieback'],
90+
'cider/piggieback should fall back to default'
91+
);
92+
});
93+
94+
test('precedence: stored values are used when nothing is configured', async () => {
95+
const stored: Record<JackInDependencyKey, string> = {
96+
nrepl: 'STORED-NREPL-1',
97+
'cider-nrepl': 'STORED-CIDER-2',
98+
'cider/piggieback': 'STORED-PIGGIE-3',
99+
};
100+
await state.extensionContext?.globalState.update(GLOBAL_STATE_KEY, stored);
101+
102+
await vscode.workspace
103+
.getConfiguration('calva')
104+
.update('jackInDependencyVersions', undefined, vscode.ConfigurationTarget.Workspace);
105+
106+
const effective = getEffectiveJackInDependencyVersions();
107+
assert.deepStrictEqual(
108+
effective,
109+
stored,
110+
'When nothing is configured, stored values should be used'
111+
);
112+
});
113+
114+
test('precedence: configured overrides stored', async () => {
115+
const stored: Record<JackInDependencyKey, string> = {
116+
nrepl: 'STORED-NREPL-1',
117+
'cider-nrepl': 'STORED-CIDER-2',
118+
'cider/piggieback': 'STORED-PIGGIE-3',
119+
};
120+
await state.extensionContext?.globalState.update(GLOBAL_STATE_KEY, stored);
121+
122+
const configured: Versions = {
123+
nrepl: 'CONFIG-NREPL-1',
124+
'cider/piggieback': 'CONFIG-PIGGIE-3',
125+
};
126+
await vscode.workspace
127+
.getConfiguration('calva')
128+
.update('jackInDependencyVersions', configured, vscode.ConfigurationTarget.Workspace);
129+
130+
const effective = getEffectiveJackInDependencyVersions();
131+
assert.strictEqual(effective.nrepl, 'CONFIG-NREPL-1', 'configured should override stored');
132+
assert.strictEqual(
133+
effective['cider/piggieback'],
134+
'CONFIG-PIGGIE-3',
135+
'configured should override stored'
136+
);
137+
assert.strictEqual(
138+
effective['cider-nrepl'],
139+
'STORED-CIDER-2',
140+
'stored should be used when not configured'
141+
);
142+
});
143+
144+
test('precedence: default is used when neither configured nor stored', async () => {
145+
const inspectedDefaults = vscode.workspace
146+
.getConfiguration('calva')
147+
.inspect<Record<JackInDependencyKey, string>>('jackInDependencyVersions');
148+
const defaults = (inspectedDefaults?.defaultValue ?? {}) as Record<JackInDependencyKey, string>;
149+
150+
await state.extensionContext?.globalState.update(GLOBAL_STATE_KEY, {});
151+
await vscode.workspace
152+
.getConfiguration('calva')
153+
.update('jackInDependencyVersions', undefined, vscode.ConfigurationTarget.Workspace);
154+
155+
const effective = getEffectiveJackInDependencyVersions();
156+
157+
assert.deepStrictEqual(
158+
effective,
159+
defaults,
160+
'effective should equal defaults when nothing is configured or stored'
161+
);
162+
});
163+
});

src/extension.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import * as converters from './converters';
4343
import * as joyride from './joyride';
4444
import * as api from './api/index';
4545
import * as depsClj from './nrepl/deps-clj';
46+
import { refreshJackInDependencyVersions } from './nrepl/jack-in-dependency-versions';
4647
import * as clojureDocs from './clojuredocs';
4748
import { capitalize } from './utilities';
4849
import * as overrides from './overrides';
@@ -186,7 +187,9 @@ async function activate(context: vscode.ExtensionContext) {
186187
);
187188
}
188189

189-
void depsClj.downloadDepsClj(context.extensionPath);
190+
void depsClj.downloadDepsClj(context.extensionPath).finally(() => {
191+
void refreshJackInDependencyVersions();
192+
});
190193

191194
if (cljKondoExtension) {
192195
void vscode.window.showWarningMessage(

src/greet.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import * as vscode from 'vscode';
22
import * as config from './config';
3+
import { getJackInVersionsDetail } from './nrepl/jack-in-dependency-versions';
34

45
export function activationGreetings(chan: vscode.OutputChannel) {
56
const conf = config.getConfig();
6-
const jackInDependencyVersions = conf.jackInDependencyVersions;
7+
const detail = getJackInVersionsDetail();
78
const clojureLspVersion = conf.clojureLspVersion;
89
const clojureLspPath = conf.clojureLspPath;
910

@@ -25,10 +26,26 @@ export function activationGreetings(chan: vscode.OutputChannel) {
2526
chan.appendLine(
2627
'Calva is utilizing cider-nrepl and clojure-lsp to create this VS Code experience.'
2728
);
28-
chan.appendLine(' nREPL dependencies configured:');
29-
for (const dep in jackInDependencyVersions) {
30-
chan.appendLine(` ${dep}: ${jackInDependencyVersions[dep]}`);
31-
}
29+
30+
chan.appendLine(' Latest available nREPL dependency versions known by Calva:');
31+
Object.keys(detail.effective).forEach((dep) => {
32+
const latest = detail.storedLatest[dep] ?? 'unknown';
33+
chan.appendLine(` ${dep}: ${latest}`);
34+
});
35+
chan.appendLine('');
36+
37+
chan.appendLine(' nREPL dependency versions:');
38+
Object.keys(detail.effective).forEach((dep) => {
39+
const source = detail.sources[dep];
40+
const sourceLabel =
41+
source === 'configured'
42+
? 'user configured override'
43+
: source === 'stored'
44+
? 'latest known by Calva'
45+
: 'Calva defaults fallback';
46+
chan.appendLine(` ${dep}: effective ${detail.effective[dep]} (${sourceLabel})`);
47+
});
48+
3249
if (clojureLspPath) {
3350
chan.appendLine(` clojure-lsp path configured: ${clojureLspPath}`);
3451
} else {

0 commit comments

Comments
 (0)