Skip to content

Commit

Permalink
Prepare to auto-install with nvim-lsp-installer (#8)
Browse files Browse the repository at this point in the history
* Remove dependency on native OpenFOAM parser

- Allows running in environments where OpenFOAM is not installed
- Full dependency on Tree-Sitter grammar for implementing basic LSP
  features

* Switch to using own version of tree-sitter

* Use upgraded tree-sitter

* Basic support for workspace symbols

* Basic support for workspace diagnostics

* Update README

* Update package-lock

* Add textdocument to deps

* Fix when keywords auto-completion is triggered

* Upgrade deps

* Switch to using  backend

* Correct package.json

* Update package-lock.json

* Minor bug fixes and better tests

* Add tsc to deps

* Bump version to 0.1.3
  • Loading branch information
FoamScience authored Jan 7, 2022
1 parent 2cda8ff commit d3baafa
Showing 8 changed files with 78 additions and 33 deletions.
16 changes: 0 additions & 16 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
@@ -20,19 +20,3 @@ jobs:
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

publish-gpr:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
registry-url: https://npm.pkg.github.com/
- run: npm install
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
3 changes: 3 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.github/**
Release/**
build/**
2 changes: 2 additions & 0 deletions bin/foam-ls
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require("../lib/foam-ls.js");
5 changes: 2 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"name": "foam-language-server",
"version": "0.1.0",
"version": "0.1.3",
"description": "A language server implementation for OpenFOAM file format.",
"keywords": [
"language",
"editor",
"openfoam"
],
"main": "lib/foam-ls.js",
"types": "lib/foam-ls.d.ts",
"scripts": {
"install": "tsc --build",
"prepublish": "tsc --build",
"clean": "tsc --build --clean",
"wasm": "node test-wasm.js",
"test": "jest"
},
"author": "Mohammed Elwardi Fadeli",
@@ -20,7 +20,7 @@
"node": "*"
},
"bin": {
"foam-ls": "./lib/foam-ls.js"
"foam-ls": "./bin/foam-ls"
},
"dependencies": {
"tree-sitter-foam": "^0.2.0",
26 changes: 17 additions & 9 deletions server/foamfile-language-service/foamDefinition.ts
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ export class FoamDefinition {
}

// Returns the macro node at current position
public getNodeUnderCursor(content: string, position: Position) {
public getMacroNodeUnderCursor(content: string, position: Position) {
let document : TextDocument = TextDocument.create("", "foam", 0, content);
let offset = document.offsetAt(position)
const tree = this.treeParser.parse(content);
@@ -58,7 +58,7 @@ export class FoamDefinition {
}
root = closestNode;
}
while(root.type != "macro" && root != tree.rootNode) {
while(root != null && root.type != "macro" && root != tree.rootNode) {
root = root.parent
}
return root;
@@ -67,7 +67,8 @@ export class FoamDefinition {
// Return the node which defines the content of passed node
// "node" is assumed to be an indentifier under a macro
// i.e. its text starts with "$"
public getNodeDefinition(node: TreeParser.SyntaxNode, content: string) {
// Returns null if current node is not a macro node
public getNodeDefinition(node: TreeParser.SyntaxNode, content: string) : TreeParser.SyntaxNode | null {

// Return the same node if not a macro-like
if (!node.text.startsWith('$')) { return node; }
@@ -83,19 +84,19 @@ export class FoamDefinition {
// retrace parents until finding a dict
// Issues:
// - Tree-Sitter walk does not like parent retracing
let nodeParents = node.text.replace('$:', '').split('.');
let nodeParents = node == null ? [] : node.text.replace('$:', '').split('.');

// This parameter denotes how much of node parents we've found
let prec = 0;

// If this is the root node (hopefully), enter the tree
if (cursor.currentNode().type == "foam") {
if (cursor.currentNode() != null && cursor.currentNode().type == "foam") {
cursor.gotoFirstChild();
}

// Find all dictionaries down to the last dictionary level just before
// the matching keyword
while (prec != nodeParents.length-1) {
while (node != null && prec != nodeParents.length-1) {
node = cursor.currentNode();
// If this is a dict matching a requested parent
if (node.type == "dict" && node.namedChild(0).text == nodeParents[prec])
@@ -109,7 +110,7 @@ export class FoamDefinition {
}

// Find the matching key-value pair
while (prec != nodeParents.length) {
while (node != null && prec != nodeParents.length) {
node = cursor.currentNode();
// If it's a dict_core, skip to the its content
if (node.type == "dict_core") {
@@ -130,8 +131,15 @@ export class FoamDefinition {
// - "Definition" for now means macro expansion
public computeDefinition(textDocument: TextDocumentIdentifier, content: string, position: Position): Location | null {

let currentNode = this.getNodeUnderCursor(content, position);
let definitionNode = this.getNodeDefinition(currentNode, content);
let currentMacroNode = this.getMacroNodeUnderCursor(content, position);
if (currentMacroNode == null) {
return Location.create(textDocument.uri, Range.create(
position.line,
position.character,
position.line,
position.character));
}
let definitionNode = this.getNodeDefinition(currentMacroNode, content);
let range = Range.create(
definitionNode.startPosition.row,
definitionNode.startPosition.column,
50 changes: 49 additions & 1 deletion tests/languageServer.test.js
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@ const foamTreeParser = require('../lib/foamfile-language-service/foamTreeParser.


// Typical dictionary content for OpenFOAM cases
// If you're testing something new, please append to this dictionary,
// don't change already existing keywords as other tests depend on the position of things here
let testContent = `
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
@@ -83,8 +85,20 @@ test('Get macro keyword definition (Absolute path)',
const syms = new parser.FoamDefinition(tp);
const expectedSyms = [32, 9];
let keys = syms.computeDefinition("", testContent, lsp.Position.create(34, 20));//.map(a => a.name);
expect([keys.range.start.line, keys.range.start.character]).toEqual(expectedSyms);
}
);

test('Return current position if definition requested for non-macro nodes',
async () => {
// Test to see if definition for $:tool.list is correctly found
const parser = require('../lib/foamfile-language-service/foamDefinition');
let tp = await foamTreeParser.getParser();
const syms = new parser.FoamDefinition(tp);
const expectedSyms = [32, 6];
let keys = syms.computeDefinition("", testContent, lsp.Position.create(32, 6));//.map(a => a.name);
expect('').toBe('');
//expect([keys.range.start.line, keys.range.start.character]).toEqual(expectedSyms);
expect([keys.range.start.line, keys.range.start.character]).toEqual(expectedSyms);
}
);

@@ -135,3 +149,37 @@ test('Get Completion item for a keyword',
expect(props[0].label).toEqual('type');
}
);

test('Get Completion item for a keyword value',
async () => {
// Testing completion on "type" keyword when typing "ty"
const parser = require('../lib/foamfile-language-service/foamAssist')
let tp = await foamTreeParser.getParser();
const markup = require('../lib/foamfile-language-service/foamPlainText');
const fc = require('../lib/foamfile-language-service/foamCompletion')
const docs = new markup.PlainTextDocumentation();
const document = lsp.TextDocument.create("", "foam", 0, testContent );
const capabs = [];
const comps = new parser.FoamAssist(document, capabs, tp);
const resolver = new fc.FoamCompletion();
props = comps.computeProposals(lsp.Position.create(34,14));
expect(props[0].label).not.toEqual('type');
}
);

test('Get Completion items for a macro on $',
async () => {
// Testing completion on "type" keyword when typing "ty"
const parser = require('../lib/foamfile-language-service/foamAssist')
let tp = await foamTreeParser.getParser();
const markup = require('../lib/foamfile-language-service/foamPlainText');
const fc = require('../lib/foamfile-language-service/foamCompletion')
const docs = new markup.PlainTextDocumentation();
const document = lsp.TextDocument.create("", "foam", 0, testContent );
const capabs = [];
const comps = new parser.FoamAssist(document, capabs, tp);
const resolver = new fc.FoamCompletion();
props = comps.computeProposals(lsp.Position.create(34,15));
expect(props[0].label).toEqual('FoamFile');
}
);
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"declaration": true,
"lib" : [ "es2016" ],
"outDir": "lib"
},

0 comments on commit d3baafa

Please sign in to comment.