Skip to content

Commit 8f71955

Browse files
committed
chore: Initial work on LSP support
1 parent da37661 commit 8f71955

File tree

16 files changed

+1661
-2
lines changed

16 files changed

+1661
-2
lines changed

package-lock.json

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

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
"storybook": "npm run storybook -w @robertoraggi/cxx-storybook",
3838
"setup-venv": "zx scripts/setup-venv.mjs",
3939
"update-tests": "zx scripts/update-tests.mjs",
40-
"cxx-gen-ast": "node packages/cxx-gen-ast"
40+
"cxx-gen-ast": "node packages/cxx-gen-ast",
41+
"cxx-gen-lsp": "node packages/cxx-gen-lsp packages/cxx-gen-lsp/metaModel.json packages/cxx-gen-lsp -o src/lsp/cxx/lsp",
42+
"download-lsp-models": "zx scripts/download-lsp-models.mjs"
4143
}
42-
}
44+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"es2021": true
5+
},
6+
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
7+
"parser": "@typescript-eslint/parser",
8+
"parserOptions": {
9+
"ecmaVersion": "latest",
10+
"sourceType": "module"
11+
},
12+
"plugins": ["@typescript-eslint"],
13+
"rules": {}
14+
}

packages/cxx-gen-lsp/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
dist/
3+
metaModel.json

packages/cxx-gen-lsp/package.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "@robertoraggi/cxx-gen-lsp",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module",
6+
"description": "Scripts to generate the LSP server for C++",
7+
"main": "./dist/main.js",
8+
"bin": {
9+
"cxx-gen-lsp": "./dist/main.js"
10+
},
11+
"scripts": {
12+
"postinstall": "npm run build",
13+
"build": "tsc",
14+
"watch": "tsc -w"
15+
},
16+
"keywords": [],
17+
"author": {
18+
"name": "Roberto Raggi",
19+
"email": "[email protected]"
20+
},
21+
"repository": {
22+
"type": "git",
23+
"url": "https://github.com/robertoraggi/cplusplus"
24+
},
25+
"license": "MIT",
26+
"devDependencies": {
27+
"@types/node": "^22.7.5",
28+
"@typescript-eslint/eslint-plugin": "^8.9.0",
29+
"@typescript-eslint/parser": "^8.9.0",
30+
"eslint": "^9.12.0",
31+
"typescript": "^5.6.3"
32+
},
33+
"dependencies": {
34+
"prettier": "^3.3.3"
35+
}
36+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (c) 2024 Roberto Raggi <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
// SOFTWARE.
20+
21+
export type Type = BaseType;
22+
23+
export type BaseTypeName = "string" | "integer" | "uinteger";
24+
25+
export type BaseType = {
26+
kind: "base";
27+
name: BaseTypeName;
28+
};
29+
30+
export type EnumerationValue = {
31+
name: string;
32+
value: string;
33+
};
34+
35+
export type MetaData = {};
36+
37+
export type Enumeration = {
38+
documentation?: string;
39+
name: string;
40+
since?: string;
41+
supportsCustomValues?: boolean;
42+
type: BaseType;
43+
values: EnumerationValue[];
44+
};
45+
46+
export type Notification = {};
47+
48+
export type Request = {};
49+
50+
export type Structure = {};
51+
52+
export type TypeAlias = {};
53+
54+
export type MetaModel = {
55+
metaData: MetaData;
56+
enumerations: Enumeration[];
57+
notifications: Notification[];
58+
requests: Request[];
59+
structures: Structure[];
60+
typeAliases: TypeAlias[];
61+
};
62+
63+
export function getEnumBaseType(enumeration: Enumeration) {
64+
switch (enumeration.type.name) {
65+
case "integer":
66+
return " : int";
67+
case "uinteger":
68+
return " : unsigned int";
69+
default:
70+
return "";
71+
}
72+
}
73+
74+
export function toUpperCamelCase(name: string) {
75+
return name[0].toUpperCase() + name.slice(1);
76+
}
77+
78+
export function getEnumeratorName(enumerator: EnumerationValue) {
79+
const name = toUpperCamelCase(enumerator.name);
80+
return `k${name}`;
81+
}
82+
83+
export function getEnumeratorInitializer(
84+
enumeration: Enumeration,
85+
enumerator: EnumerationValue
86+
) {
87+
if (enumeration.type.name === "string") {
88+
return "";
89+
}
90+
return ` = ${enumerator.value}`;
91+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const copyrightHeader = `// Copyright (c) 2024 Roberto Raggi <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
// SOFTWARE.`;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) 2024 Roberto Raggi <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
// SOFTWARE.
20+
21+
import { getEnumeratorName, MetaModel } from "./MetaModel.js";
22+
23+
import path from "node:path";
24+
import { writeFile } from "node:fs/promises";
25+
import { copyrightHeader } from "./copyrightHeader.js";
26+
27+
export async function gen_enums_cc({
28+
model,
29+
outputDirectory,
30+
}: {
31+
model: MetaModel;
32+
outputDirectory: string;
33+
}) {
34+
let out = "";
35+
36+
const emit = (s: string = "") => {
37+
out += `${s}\n`;
38+
};
39+
40+
emit(`#include <cxx/lsp/enums.h>`);
41+
emit();
42+
emit(`namespace cxx::lsp {`);
43+
44+
model.enumerations.forEach((enumeration) => {
45+
emit();
46+
emit(`auto to_string(${enumeration.name} value) -> std::string {`);
47+
emit(` switch (value) {`);
48+
49+
enumeration.values.forEach((enumerator) => {
50+
const enumeratorName = getEnumeratorName(enumerator);
51+
52+
const text =
53+
enumeration.type.name === "string" ? enumerator.value : enumerator.name;
54+
55+
emit(` case ${enumeration.name}::${enumeratorName}:`);
56+
emit(` return "${text}";`);
57+
});
58+
59+
emit(` }`);
60+
emit(`}`);
61+
});
62+
63+
emit();
64+
emit(`} // namespace cxx::lsp`);
65+
66+
const outputFile = path.join(outputDirectory, "enums.cc");
67+
await writeFile(outputFile, out);
68+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright (c) 2024 Roberto Raggi <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
// SOFTWARE.
20+
21+
import {
22+
getEnumBaseType,
23+
getEnumeratorInitializer,
24+
getEnumeratorName,
25+
MetaModel,
26+
} from "./MetaModel.js";
27+
28+
import path from "node:path";
29+
import { writeFile } from "node:fs/promises";
30+
31+
export async function gen_enums_h({
32+
model,
33+
outputDirectory,
34+
}: {
35+
model: MetaModel;
36+
outputDirectory: string;
37+
}) {
38+
let out = "";
39+
40+
const emit = (s: string = "") => {
41+
out += `${s}\n`;
42+
};
43+
44+
emit(`#pragma once`);
45+
emit();
46+
emit();
47+
emit(`#include <string>`);
48+
emit();
49+
emit(`namespace cxx::lsp {`);
50+
51+
model.enumerations.forEach((enumeration) => {
52+
emit();
53+
const enumBaseType = getEnumBaseType(enumeration);
54+
emit(`enum class ${enumeration.name}${enumBaseType} {`);
55+
enumeration.values.forEach((value) => {
56+
const enumeratorName = getEnumeratorName(value);
57+
const enumeratorInitializer = getEnumeratorInitializer(
58+
enumeration,
59+
value
60+
);
61+
emit(` ${enumeratorName}${enumeratorInitializer},`);
62+
});
63+
emit(`};`);
64+
});
65+
emit();
66+
model.enumerations.forEach((enumeration) => {
67+
emit(`auto to_string(${enumeration.name} value) -> std::string;`);
68+
});
69+
emit();
70+
emit(`} // namespace cxx::lsp`);
71+
72+
const outputFile = path.join(outputDirectory, "enums.h");
73+
await writeFile(outputFile, out);
74+
}

0 commit comments

Comments
 (0)