Skip to content
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
20 changes: 18 additions & 2 deletions server/src/analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,30 @@ export default class Analyzer {
* @param uri uri to the library root
* @param isWorkspace `true` if this is a user workspace/project, `false` if
* this is a library.
* @returns `true` if the library was loaded, `false` if it was skipped because
* the path does not exist or does not contain a `package.mo`.
*/
public async loadLibrary(uri: LSP.URI, isWorkspace: boolean): Promise<void> {
public async loadLibrary(uri: LSP.URI, isWorkspace: boolean): Promise<boolean> {
const isLibrary = (folderPath: string) =>
fsSync.existsSync(path.join(folderPath, 'package.mo'));

const libraryPath = url.fileURLToPath(uri);
if (!fsSync.existsSync(libraryPath)) {
logger.debug(
`Skipping ${isWorkspace ? 'workspace' : 'library'} at '${libraryPath}': path does not exist.`,
);
return false;
}

if (!isWorkspace || isLibrary(libraryPath)) {
if (!isLibrary(libraryPath)) {
logger.debug(`Skipping library at '${libraryPath}': no 'package.mo' found.`);
return false;
}

const lib = await ModelicaLibrary.load(this.#project, libraryPath, isWorkspace);
this.#project.addLibrary(lib);
return;
return true;
}

// TODO: go deeper... something like `TreeSitterUtil.forEach` but for files
Expand All @@ -94,6 +108,8 @@ export default class Analyzer {
const library = await ModelicaLibrary.load(this.#project, nested, isWorkspace);
this.#project.addLibrary(library);
}

return true;
}

/**
Expand Down
23 changes: 21 additions & 2 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,13 @@ export class ModelicaServer {
const analyzer = new Analyzer(parser);
if (workspaceFolders != null) {
for (const workspace of workspaceFolders) {
await analyzer.loadLibrary(workspace.uri, true);
try {
await analyzer.loadLibrary(workspace.uri, true);
} catch (err) {
logger.error(
`Failed to load workspace '${workspace.uri}': ${err instanceof Error ? err.message : err}`,
);
}
}
}

Expand All @@ -105,7 +111,20 @@ export class ModelicaServer {
for (const libraryPath of configuredLibraries) {
const libraryUri = url.pathToFileURL(path.resolve(libraryPath)).toString();
logger.debug(`Loading configured library '${libraryPath}'`);
await analyzer.loadLibrary(libraryUri, false);
try {
const loaded = await analyzer.loadLibrary(libraryUri, false);
if (!loaded) {
const message =
`Could not load Modelica library '${libraryPath}': the path does not exist or has no ` +
`'package.mo'. Remove or fix this entry in the "modelica.libraries" setting to stop loading it.`;
logger.warn(message);
connection.window.showWarningMessage(message);
}
} catch (err) {
logger.error(
`Failed to load configured library '${libraryPath}': ${err instanceof Error ? err.message : err}`,
);
}
}

logger.debug('Initialized');
Expand Down
65 changes: 65 additions & 0 deletions server/src/test/analyzer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* This file is part of OpenModelica.
*
* Copyright (c) 1998-2024, Open Source Modelica Consortium (OSMC),
* c/o Linköpings universitet, Department of Computer and Information Science,
* SE-58183 Linköping, Sweden.
*
* All rights reserved.
*
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
* THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
* VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
*
* The OpenModelica software and the OSMC (Open Source Modelica Consortium)
* Public License (OSMC-PL) are obtained from OSMC, either from the above
* address, from the URLs:
* http://www.openmodelica.org or
* https://github.com/OpenModelica/ or
* http://www.ida.liu.se/projects/OpenModelica,
* and in the OpenModelica distribution.
*
* GNU AGPL version 3 is obtained from:
* https://www.gnu.org/licenses/licenses.html#GPL
*
* This program is distributed WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
*
* See the full OSMC Public License conditions for more details.
*
*/

import assert from 'node:assert/strict';
import * as path from 'node:path';
import * as url from 'node:url';

import Analyzer from '../analyzer';
import { initializeParser } from '../parser';

describe('Analyzer.loadLibrary', () => {
let analyzer: Analyzer;

beforeEach(async () => {
const parser = await initializeParser();
analyzer = new Analyzer(parser);
});

// Regression test for https://github.com/OpenModelica/modelica-language-server/issues/49
it('skips a configured library whose path does not exist without throwing', async () => {
const missingPath = path.join(__dirname, 'this-library-does-not-exist');
const missingUri = url.pathToFileURL(missingPath).toString();

assert.equal(await analyzer.loadLibrary(missingUri, false), false);
});

it('skips a workspace whose path does not exist without throwing', async () => {
const missingPath = path.join(__dirname, 'this-workspace-does-not-exist');
const missingUri = url.pathToFileURL(missingPath).toString();

assert.equal(await analyzer.loadLibrary(missingUri, true), false);
});
});
Loading