Merge branch 'main' into parser-tests-with-pytest
This commit is contained in:
commit
add32471d8
9 changed files with 338 additions and 12 deletions
|
@ -156,14 +156,16 @@ fn builtinCompletions(arena: std.mem.Allocator, spec: *const Spec) ![]lsp.Comple
|
|||
}
|
||||
|
||||
for (spec.variables) |variable| {
|
||||
var signature = std.ArrayList(u8).init(arena);
|
||||
try signature.writer().print("{}", .{variable.modifiers});
|
||||
try signature.appendSlice(" ");
|
||||
try signature.appendSlice(variable.type);
|
||||
var anonymous_signature = std.ArrayList(u8).init(arena);
|
||||
try writeVariableSignature(variable, anonymous_signature.writer(), .{ .names = false });
|
||||
|
||||
var named_signature = std.ArrayList(u8).init(arena);
|
||||
try writeVariableSignature(variable, named_signature.writer(), .{ .names = true });
|
||||
|
||||
try completions.append(.{
|
||||
.label = variable.name,
|
||||
.labelDetails = .{ .detail = signature.items },
|
||||
.labelDetails = .{ .detail = anonymous_signature.items },
|
||||
.detail = named_signature.items,
|
||||
.kind = .variable,
|
||||
.documentation = try itemDocumentation(arena, variable),
|
||||
});
|
||||
|
@ -207,6 +209,31 @@ fn itemDocumentation(arena: std.mem.Allocator, item: anytype) !lsp.MarkupContent
|
|||
return .{ .kind = .markdown, .value = try documentation.toOwnedSlice() };
|
||||
}
|
||||
|
||||
fn writeVariableSignature(
|
||||
variable: Spec.Variable,
|
||||
writer: anytype,
|
||||
options: struct { names: bool },
|
||||
) !void {
|
||||
if (!std.meta.eql(variable.modifiers, .{ .in = true })) {
|
||||
try writer.print("{}", .{variable.modifiers});
|
||||
try writer.writeAll(" ");
|
||||
}
|
||||
|
||||
try writer.writeAll(variable.type);
|
||||
|
||||
if (options.names) {
|
||||
try writer.writeAll(" ");
|
||||
try writer.writeAll(variable.name);
|
||||
|
||||
if (variable.default_value) |value| {
|
||||
try writer.writeAll(" = ");
|
||||
try writer.writeAll(value);
|
||||
}
|
||||
|
||||
try writer.writeAll(";");
|
||||
}
|
||||
}
|
||||
|
||||
fn writeFunctionSignature(
|
||||
function: Spec.Function,
|
||||
writer: anytype,
|
||||
|
|
|
@ -314,6 +314,7 @@ fn formatNode(tree: parse.Tree, current: usize, writer: anytype) !void {
|
|||
.array,
|
||||
.array_specifier,
|
||||
.selection,
|
||||
.parenthized,
|
||||
=> {
|
||||
const children = tree.children(current);
|
||||
for (children.start..children.end) |child| {
|
||||
|
@ -321,6 +322,14 @@ fn formatNode(tree: parse.Tree, current: usize, writer: anytype) !void {
|
|||
}
|
||||
},
|
||||
|
||||
.conditional => {
|
||||
const children = tree.children(current);
|
||||
for (children.start..children.end) |child| {
|
||||
if (child != children.start) writer.writeSpace();
|
||||
try formatNode(tree, child, writer);
|
||||
}
|
||||
},
|
||||
|
||||
// emit tokens separated by spaces
|
||||
inline else => |tag| {
|
||||
const operators = comptime parse.assignment_operators.unionWith(parse.infix_operators);
|
||||
|
@ -362,7 +371,6 @@ fn needsLeadingSpace(tag: parse.Tag) bool {
|
|||
.@",",
|
||||
.parameter_list,
|
||||
.array,
|
||||
.array_specifier,
|
||||
=> false,
|
||||
else => true,
|
||||
};
|
||||
|
@ -573,6 +581,42 @@ test "format field selection" {
|
|||
);
|
||||
}
|
||||
|
||||
test "format ternary condition" {
|
||||
try expectIsFormatted(
|
||||
\\void main() {
|
||||
\\ int foo = a ? b : c;
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "format parenthized" {
|
||||
try expectIsFormatted(
|
||||
\\void main() {
|
||||
\\ int foo = (1 + 1);
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "format assign array" {
|
||||
try expectIsFormatted(
|
||||
\\void main() {
|
||||
\\ int foo = bar[123];
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "format array declaration" {
|
||||
try expectIsFormatted(
|
||||
\\void main() {
|
||||
\\ int[2] foo[123];
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
fn expectIsFormatted(source: []const u8) !void {
|
||||
try expectFormat(source, source);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
**Requirements:** `python 3.10` and `requirements.txt`.
|
||||
|
||||
*The `glsl_analyzer` version you want to test must be available in your PATH.*
|
||||
|
||||
You can run the tests by directly invoking `pytest`:
|
||||
|
||||
```sh
|
||||
|
|
77
tests/hover-and-completion/buffers.frag
Normal file
77
tests/hover-and-completion/buffers.frag
Normal file
|
@ -0,0 +1,77 @@
|
|||
#version 430 core
|
||||
|
||||
|
||||
// Simple name resolution for global and local scopes.
|
||||
layout(std140, binding = 0) uniform UBuffer0 {
|
||||
mat4 field0;
|
||||
};
|
||||
|
||||
layout(std140, binding = 1) uniform UBuffer1 {
|
||||
vec4 field0;
|
||||
} ubuffer1;
|
||||
|
||||
layout(std430, binding = 0) buffer SSBuffer0 {
|
||||
mat3 field1[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) buffer SSBuffer1 {
|
||||
mat2 field1[];
|
||||
} ssbuffer1;
|
||||
|
||||
layout(std430, binding = 2) buffer SSBuffer2 {
|
||||
vec3 field0[];
|
||||
} ssbuffer2;
|
||||
|
||||
// Nested aggregates.
|
||||
struct AAA {
|
||||
int field0;
|
||||
};
|
||||
|
||||
layout(std430, binding = 3) buffer SSBuffer3 {
|
||||
AAA aaa[][3];
|
||||
} ssbuffer3;
|
||||
|
||||
// Nested with repeating names.
|
||||
struct BBB {
|
||||
uint ssbuffer4;
|
||||
};
|
||||
|
||||
struct CCC {
|
||||
BBB ssbuffer4;
|
||||
};
|
||||
|
||||
layout(std430, binding = 4) buffer SSBuffer4 {
|
||||
CCC ssbuffer4;
|
||||
} ssbuffer4;
|
||||
|
||||
// Arrays of uniform buffers.
|
||||
layout(std140, binding = 2) uniform UBuffer2 {
|
||||
mat2 field0;
|
||||
} ubuffer2[3];
|
||||
|
||||
// Qualifiers.
|
||||
layout(std430, binding = 5) restrict writeonly coherent buffer SSBuffer5 {
|
||||
bool field0;
|
||||
} ssbuffer5;
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
field0; // <mat4>
|
||||
field1; // <mat3[]>
|
||||
// <layout(std140, binding = 1) uniform UBuffer1 { vec4 field0; }> . <vec4>
|
||||
ubuffer1.field0;
|
||||
// <layout(std430, binding = 1) buffer SSBuffer1 { mat2 field1[]; }> . <mat2[]>
|
||||
ssbuffer1.field1;
|
||||
// <layout(std430, binding = 2) buffer SSBuffer2 { vec3 field0[]; }> . <vec3[]>
|
||||
ssbuffer2.field0;
|
||||
// <layout(std430, binding = 3) buffer SSBuffer3 { AAA aaa[][3]; }> . <AAA[][3]> . <int>
|
||||
ssbuffer3.aaa[0][0].field0;
|
||||
// <layout(std430, binding = 4) buffer SSBuffer4 { CCC ssbuffer4; }> . <CCC> . <BBB> . <uint>
|
||||
ssbuffer4.ssbuffer4.ssbuffer4.ssbuffer4;
|
||||
// <layout(std140, binding = 2) uniform UBuffer2 { mat2 field0; }[3]> . <mat2>
|
||||
ubuffer2[0].field0;
|
||||
// <layout(std430, binding = 5) restrict writeonly coherent buffer SSBuffer5 { bool field0; }> . <bool>
|
||||
ssbuffer5.field0;
|
||||
|
||||
}
|
23
tests/hover-and-completion/hover_positions.frag
Normal file
23
tests/hover-and-completion/hover_positions.frag
Normal file
|
@ -0,0 +1,23 @@
|
|||
#version 430 core
|
||||
|
||||
int value = 0;
|
||||
const int value_ = 1;
|
||||
|
||||
void foo() {
|
||||
// Past-the-end hovers.
|
||||
// Should only trigger when cursor is adjacent to the token.
|
||||
value;
|
||||
|
||||
value ;
|
||||
value
|
||||
;
|
||||
|
||||
value/* w */;
|
||||
value//
|
||||
;
|
||||
|
||||
value;value_;
|
||||
|
||||
}
|
||||
|
||||
|
29
tests/hover-and-completion/images_and_samplers.frag
Normal file
29
tests/hover-and-completion/images_and_samplers.frag
Normal file
|
@ -0,0 +1,29 @@
|
|||
#version 430 core
|
||||
|
||||
|
||||
uniform layout(rgba8, binding = 0) image2D image2d_0;
|
||||
uniform layout(rgba16i, binding = 1) iimageCubeArray iimagecubearray_1;
|
||||
uniform layout(rgba16_snorm, binding = 2) restrict writeonly coherent image2DMSArray image2dmsarray_2;
|
||||
|
||||
uniform sampler2D sampler2d_0;
|
||||
uniform isamplerCubeArray isamplercubearray_1;
|
||||
uniform sampler2DMSArray sampler2dmsarray_2;
|
||||
|
||||
|
||||
void main() {
|
||||
// <uniform layout(rgba8, binding = 0) image2D>
|
||||
image2d_0;
|
||||
// <uniform layout(rgba16i, binding = 1) iimageCubeArray>
|
||||
iimagecubearray_1;
|
||||
// <uniform layout(rgba16_snorm, binding = 2) restrict writeonly coherent image2DMSArray>
|
||||
image2dmsarray_2;
|
||||
|
||||
// <unifrom sampler2D>
|
||||
sampler2d_0;
|
||||
// <uniform isamplerCubeArray>
|
||||
isamplercubearray_1;
|
||||
// <uniform sampler2DMSArray>
|
||||
sampler2dmsarray_2;
|
||||
|
||||
}
|
||||
|
40
tests/hover-and-completion/static_arrays.frag
Normal file
40
tests/hover-and-completion/static_arrays.frag
Normal file
|
@ -0,0 +1,40 @@
|
|||
#version 430 core
|
||||
|
||||
|
||||
int iarr[3] = { 1, 2, 3 };
|
||||
int iarr_implicit[];
|
||||
int iarr_nested[2][3];
|
||||
const int ciarr[3] = { 1, 2, 3 };
|
||||
const int ciarr_nested_implicit[][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
|
||||
|
||||
struct Elem {
|
||||
int field1;
|
||||
};
|
||||
|
||||
const Elem elements[] = { {1}, {2}, {3} };
|
||||
|
||||
void main() {
|
||||
|
||||
ciarr;
|
||||
const int ciarr[] = { 1, 2, 3 };
|
||||
ciarr;
|
||||
|
||||
iarr_implicit;
|
||||
|
||||
iarr_nested[0] = ciarr;
|
||||
|
||||
ciarr_nested_implicit;
|
||||
|
||||
}
|
||||
|
||||
void foo(const Elem elements[3]) {
|
||||
|
||||
elements;
|
||||
|
||||
// Arrays have no fields.
|
||||
// v
|
||||
elements. ;
|
||||
|
||||
elements[0].field1;
|
||||
|
||||
}
|
|
@ -13,7 +13,6 @@ base_directory = pathlib.Path(__file__).parent.resolve()
|
|||
|
||||
|
||||
files_to_test = [
|
||||
# TODO: Arrays, UBOs and SSBOs, images/samplers.
|
||||
FileToTest(
|
||||
path="glsl-samples/well-formed/basic.vert",
|
||||
hover_test_args=(
|
||||
|
@ -188,5 +187,93 @@ files_to_test = [
|
|||
(29, 8, None),
|
||||
)
|
||||
),
|
||||
FileToTest(
|
||||
path="hover-and-completion/hover_positions.frag",
|
||||
hover_test_args=(
|
||||
# Past-the-end hover should only trigger when cursor is adjacent to the token.
|
||||
( 9, 10, "int"),
|
||||
( 9, 11, None),
|
||||
# Past-the-end break by space and newline.
|
||||
(11, 11, None),
|
||||
(13, 1, None),
|
||||
# Past-the-end break by comments.
|
||||
(15, 17, None),
|
||||
(17, 1, None),
|
||||
# Nearby identifiers.
|
||||
(19, 10, "int"),
|
||||
(19, 11, "const int"),
|
||||
)
|
||||
),
|
||||
FileToTest(
|
||||
path="hover-and-completion/static_arrays.frag",
|
||||
hover_test_args=(
|
||||
# Shadowing.
|
||||
(18, 5, "const int[3]"),
|
||||
(20, 5, "const int[]"),
|
||||
# Implicit size.
|
||||
(22, 5, "int[]"),
|
||||
# Nested arrays.
|
||||
(24, 5, "int[2][3]"),
|
||||
# Nested with partially implicit size.
|
||||
(26, 5, "const int[][3]"),
|
||||
# Arrays of structs.
|
||||
(32, 5, "const Elem[3]"),
|
||||
(38, 5, "const Elem[3]"),
|
||||
(38, 17, "int"),
|
||||
),
|
||||
completion_test_args=(
|
||||
# Arrays of structs.
|
||||
ExpectFail(36, 14, None, \
|
||||
reason="Bug. Arrays have no fields."),
|
||||
(38, 17, ("field1",)),
|
||||
),
|
||||
),
|
||||
FileToTest(
|
||||
path="hover-and-completion/buffers.frag",
|
||||
hover_test_args=(
|
||||
# Global buffer fields.
|
||||
(60, 5, "mat4"),
|
||||
(61, 5, "mat3[]"),
|
||||
# Scoped buffer fields.
|
||||
(63, 5, "layout(std140, binding = 1) uniform UBuffer1 { vec4 field0; }"),
|
||||
(63, 14, "vec4"),
|
||||
(65, 5, "layout(std430, binding = 1) buffer SSBuffer1 { mat2 field1[]; }"),
|
||||
(65, 15, "mat2[]"),
|
||||
(67, 5, "layout(std430, binding = 2) buffer SSBuffer2 { vec3 field0[]; }"),
|
||||
(67, 15, "vec3[]"),
|
||||
# Nested fields.
|
||||
(69, 5, "layout(std430, binding = 3) buffer SSBuffer3 { AAA aaa[][3]; }"),
|
||||
(69, 15, "AAA[][3]"),
|
||||
(69, 25, "int"),
|
||||
# Nested structs with repeating names.
|
||||
(71, 5, "layout(std430, binding = 4) buffer SSBuffer4 { CCC ssbuffer4; }"),
|
||||
(71, 15, "CCC"),
|
||||
(71, 25, "BBB"),
|
||||
(71, 35, "uint"),
|
||||
# Array of uniform buffers.
|
||||
(73, 5, "layout(std140, binding = 2) uniform UBuffer2 { mat2 field0; }[3]"),
|
||||
(73, 17, "mat2"),
|
||||
# Qualifiers.
|
||||
(75, 5, "layout(std430, binding = 5) restrict writeonly coherent buffer SSBuffer5 { bool field0; }"),
|
||||
(75, 15, "bool"),
|
||||
),
|
||||
completion_test_args=(
|
||||
# Nested structs with repeating names.
|
||||
(71, 15, ("ssbuffer4",)),
|
||||
(71, 25, ("ssbuffer4",)),
|
||||
(71, 35, ("ssbuffer4",)),
|
||||
),
|
||||
),
|
||||
FileToTest(
|
||||
path="hover-and-completion/images_and_samplers.frag",
|
||||
hover_test_args=(
|
||||
(15, 5, "uniform layout(rgba8, binding = 0) image2D"),
|
||||
(17, 5, "uniform layout(rgba16i, binding = 1) iimageCubeArray"),
|
||||
(19, 5, "uniform layout(rgba16_snorm, binding = 2) restrict writeonly coherent image2DMSArray"),
|
||||
(22, 5, "uniform sampler2D"),
|
||||
(24, 5, "uniform isamplerCubeArray"),
|
||||
(26, 5, "uniform sampler2DMSArray"),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
|
|
|
@ -149,11 +149,8 @@ async def test_hover(
|
|||
def expect_function(expected: str|set[str], result: lspt.Hover):
|
||||
def strip_md(mdtext: lspt.MarkupContent) -> list[str]:
|
||||
|
||||
text = mdtext.value
|
||||
entries = text.split(sep="---")
|
||||
|
||||
for i, entry in enumerate(entries):
|
||||
entries[i] = strip_until_naked(entry)
|
||||
text = strip_until_naked(mdtext.value)
|
||||
entries = text.split(sep="\n")
|
||||
|
||||
return entries
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue