Skip to content
Draft
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
401 changes: 55 additions & 346 deletions apps/nxls/src/main.ts

Large diffs are not rendered by default.

410 changes: 410 additions & 0 deletions apps/nxls/src/requests.ts

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions apps/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@
"command": "nxConsole.showProblems",
"when": "view == nxProjects && viewItem == projectGraphError",
"group": "inline@1"
},
{
"command": "nxConsole.restartDaemonWatcher",
"when": "view == nxProjects && viewItem == daemonWatcherNotRunning",
"group": "inline@1"
}
],
"editor/title": [
Expand Down Expand Up @@ -935,6 +940,12 @@
"command": "nxConsole.showProblems",
"icon": "$(eye)"
},
{
"category": "Nx",
"title": "Restart Daemon Watcher",
"command": "nxConsole.restartDaemonWatcher",
"icon": "$(refresh)"
},
{
"category": "Nx Migrate",
"title": "Refresh View",
Expand Down
7 changes: 7 additions & 0 deletions libs/language-server/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,16 @@ export const NxWorkspaceRefreshNotification: NotificationType<void> =
export const NxWorkspaceRefreshStartedNotification: NotificationType<void> =
new NotificationType('nx/refreshWorkspaceStarted');

export const NxWatcherOperationalNotification: NotificationType<{
isOperational: boolean;
}> = new NotificationType('nx/fileWatcherOperational');

export const NxStopDaemonRequest: RequestType<undefined, undefined, unknown> =
new RequestType('nx/stopDaemon');

export const NxStartDaemonRequest: RequestType<undefined, undefined, unknown> =
new RequestType('nx/startDaemon');

export const NxWorkspaceRequest: RequestType<
{ reset: boolean },
NxWorkspace,
Expand Down
81 changes: 0 additions & 81 deletions libs/language-server/watcher/src/lib/parcel-watcher.ts

This file was deleted.

211 changes: 142 additions & 69 deletions libs/language-server/watcher/src/lib/watcher.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
import { lspLogger } from '@nx-console/language-server-utils';
import { getNxVersion } from '@nx-console/shared-nx-workspace-info';
import { gte, NxVersion } from '@nx-console/nx-version';
import {
getNxDaemonClient,
getNxVersion,
} from '@nx-console/shared-nx-workspace-info';
import { debounce } from '@nx-console/shared-utils';
import { DaemonWatcher, NativeWatcher } from '@nx-console/shared-watcher';
import { ParcelWatcher } from './parcel-watcher';
import { gte } from '@nx-console/nx-version';
import {
DaemonWatcher,
DaemonWatcherCallback,
NativeWatcher,
PassiveDaemonWatcher,
} from '@nx-console/shared-watcher';

let _daemonWatcher: DaemonWatcher | undefined;
let _passiveDaemonWatcher: PassiveDaemonWatcher | undefined;
let _nativeWatcher: NativeWatcher | undefined;
let _daemonWatcher: DaemonWatcher | undefined;

export async function cleanupAllWatchers(): Promise<void> {
const cleanupPromises: Promise<void>[] = [];

if (_nativeWatcher) {
if (_passiveDaemonWatcher) {
cleanupPromises.push(
_nativeWatcher.stop().catch((e) => {
Promise.resolve(_passiveDaemonWatcher.dispose()).catch((e) => {
lspLogger.log(
'Error stopping native watcher during global cleanup: ' + e,
'Error stopping daemon watcher during global cleanup: ' + e,
);
}),
);
_nativeWatcher = undefined;
_passiveDaemonWatcher = undefined;
}

if (_daemonWatcher) {
Expand All @@ -33,82 +41,147 @@ export async function cleanupAllWatchers(): Promise<void> {
_daemonWatcher = undefined;
}

if (_nativeWatcher) {
cleanupPromises.push(
_nativeWatcher.stop().catch((e) => {
lspLogger.log(
'Error stopping native watcher during global cleanup: ' + e,
);
}),
);
_nativeWatcher = undefined;
}

await Promise.all(cleanupPromises);
}

export async function languageServerWatcher(
workspacePath: string,
callback: () => unknown,
callback: DaemonWatcherCallback,
watcherOperationalCallback?: (isOperational: boolean) => void,
): Promise<() => Promise<void>> {
const nxVersion = await getNxVersion(workspacePath);
if (!nxVersion || !gte(nxVersion, '16.4.0')) {
lspLogger.log(
'File watching is not supported for Nx versions below 16.4.0.',
);
watcherOperationalCallback?.(false);
return async () => {
lspLogger.log('unregistering empty watcher');
};
}

if (gte(nxVersion, '22.0.0')) {
return registerPassiveDaemonWatcher(
workspacePath,
callback,
watcherOperationalCallback,
);
} else {
// older versions don't have this granular watcher tracking so we just assume true
watcherOperationalCallback?.(true);
return registerOldWatcher(workspacePath, nxVersion, callback);
}
}

async function registerPassiveDaemonWatcher(
workspacePath: string,
callback: DaemonWatcherCallback,
watcherOperationalCallback?: (isOperational: boolean) => void,
): Promise<() => Promise<void>> {
const daemonClient = await getNxDaemonClient(workspacePath, lspLogger);

if (!daemonClient.daemonClient.enabled()) {
lspLogger.log('Daemon client is not enabled, file watching not available.');
return async () => {
lspLogger.log('unregistering empty watcher');
};
}
try {
_passiveDaemonWatcher = new PassiveDaemonWatcher(
workspacePath,
lspLogger,
watcherOperationalCallback,
);
await _passiveDaemonWatcher.start();
_passiveDaemonWatcher.listen((error, projectGraphAndSourceMaps) => {
callback(error, projectGraphAndSourceMaps);
});
return async () => {
if (_passiveDaemonWatcher) {
return _passiveDaemonWatcher.dispose();
}
};
} catch (e) {
lspLogger.log(
'Error starting passive daemon watcher: ' + (e as Error).message,
);
return async () => {
lspLogger.log('unregistering empty watcher');
};
}
}

async function registerOldWatcher(
workspacePath: string,
nxVersion: NxVersion,
callback: () => void,
): Promise<() => Promise<void>> {
const version = await getNxVersion(workspacePath);
const debouncedCallback = debounce(callback, 1000);

if (gte(version, '16.4.0')) {
if (process.platform === 'win32') {
if (_nativeWatcher) {
try {
await _nativeWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping previous native watcher: ' + e);
}
if (process.platform === 'win32') {
if (_nativeWatcher) {
try {
await _nativeWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping previous native watcher: ' + e);
}
_nativeWatcher = undefined;
}
const nativeWatcher = new NativeWatcher(
workspacePath,
debouncedCallback,
lspLogger,
);
_nativeWatcher = nativeWatcher;
return async () => {
lspLogger.log('Unregistering file watcher');
try {
await nativeWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping native watcher during cleanup: ' + e);
}
if (_nativeWatcher === nativeWatcher) {
_nativeWatcher = undefined;
}
const nativeWatcher = new NativeWatcher(
workspacePath,
debouncedCallback,
lspLogger,
);
_nativeWatcher = nativeWatcher;
return async () => {
lspLogger.log('Unregistering file watcher');
try {
await nativeWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping native watcher during cleanup: ' + e);
}
if (_nativeWatcher === nativeWatcher) {
_nativeWatcher = undefined;
}
};
} else {
if (_daemonWatcher) {
try {
_daemonWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping previous daemon watcher: ' + e);
}
_daemonWatcher = undefined;
};
} else {
if (_daemonWatcher) {
try {
_daemonWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping previous daemon watcher: ' + e);
}
const daemonWatcher = new DaemonWatcher(
workspacePath,
version,
debouncedCallback,
lspLogger,
);
_daemonWatcher = daemonWatcher;

await daemonWatcher.start();
return async () => {
lspLogger.log('Unregistering file watcher');
try {
await daemonWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping daemon watcher during cleanup: ' + e);
}
if (_daemonWatcher === daemonWatcher) {
_daemonWatcher = undefined;
}
};
_daemonWatcher = undefined;
}
} else {
lspLogger.log('Nx version <16.4.0, using @parcel/watcher');
const parcelWatcher = new ParcelWatcher(workspacePath, debouncedCallback);
const daemonWatcher = new DaemonWatcher(
workspacePath,
nxVersion,
debouncedCallback,
lspLogger,
);
_daemonWatcher = daemonWatcher;

await daemonWatcher.start();
return async () => {
lspLogger.log('Unregistering file watcher');
try {
parcelWatcher.stop();
await daemonWatcher.stop();
} catch (e) {
lspLogger.log('Error stopping parcel watcher during cleanup: ' + e);
lspLogger.log('Error stopping daemon watcher during cleanup: ' + e);
}
if (_daemonWatcher === daemonWatcher) {
_daemonWatcher = undefined;
}
};
}
Expand Down
5 changes: 1 addition & 4 deletions libs/language-server/watcher/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
"files": [],
"include": [],
"references": [
{
"path": "../../shared/nx-version"
},
{
"path": "../../shared/watcher"
},
Expand All @@ -16,7 +13,7 @@
"path": "../../shared/nx-workspace-info"
},
{
"path": "../../shared/npm"
"path": "../../shared/nx-version"
},
{
"path": "../utils"
Expand Down
Loading
Loading