df_ls_structure 0.3.0-rc.1

A language server for Dwarf Fortress RAW files
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
use df_ls_core::{AllowEmpty, Choose, Clamp, Reference, ReferenceTo};
use df_ls_lexical_analysis::test_utils::LexerTestBuilder;
use df_ls_structure::*;
use df_ls_syntax_analysis::test_utils::SyntaxTestBuilder;

#[test]
fn test_reaction() {
    SyntaxTestBuilder::from_lexer_test_builder(
        LexerTestBuilder::test_source(
            "reaction_other

            [OBJECT:REACTION]

            [REACTION:TAN_A_HIDE]
                [NAME:tan a hide]
                [BUILDING:TANNER:CUSTOM_T]
                [REAGENT:A:1:NONE:NONE:NONE:NONE][USE_BODY_COMPONENT][UNROTTEN]
                    [HAS_MATERIAL_REACTION_PRODUCT:TAN_MAT]

                In the product, if you want to use the reagent's material itself, use NONE instead of a reaction product class (TAN_MAT in this example).

                [PRODUCT:100:1:SKIN_TANNED:NONE:GET_MATERIAL_FROM_REAGENT:A:TAN_MAT]
                [SKILL:TANNER]
                [AUTOMATIC]

            [REACTION:RENDER_FAT]
                [NAME:render fat]
                [BUILDING:KITCHEN:HOTKEY_KITCHEN_RENDER_FAT]
                [REAGENT:A:150:GLOB:NONE:NONE:NONE][REACTION_CLASS:FAT][UNROTTEN]
                    [HAS_MATERIAL_REACTION_PRODUCT:RENDER_MAT]
                [PRODUCT:100:1:GLOB:NONE:GET_MATERIAL_FROM_REAGENT:A:RENDER_MAT]
                [SKILL:COOK]
                [AUTOMATIC]

            [REACTION:MAKE_SOAP_FROM_TALLOW]
                [NAME:make soap from tallow]
                [BUILDING:SOAP_MAKER:CUSTOM_T]
                [REAGENT:LYE:150:LIQUID_MISC:NONE:LYE]
                [REAGENT:LYE_CONTAINER:1:NONE:NONE:NONE:NONE]
                    [CONTAINS:LYE]
                    [PRESERVE_REAGENT]
                    [DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
                [REAGENT:TALLOW:150:GLOB:NONE:NONE:NONE][REACTION_CLASS:TALLOW][UNROTTEN]
                    [HAS_MATERIAL_REACTION_PRODUCT:SOAP_MAT]
                [PRODUCT:100:1:BAR:NONE:GET_MATERIAL_FROM_REAGENT:TALLOW:SOAP_MAT]
                    [PRODUCT_DIMENSION:150]
                [SKILL:SOAP_MAKING]
                [SKILL_IP:40]
                [SKILL_ROLL_RANGE:11:6]
                [ATTRIBUTE_IP:20]

            [REACTION:MAKE_SOAP_FROM_OIL]
                [NAME:make soap from oil]
                [BUILDING:SOAP_MAKER:CUSTOM_O]
                [REAGENT:LYE:150:LIQUID_MISC:NONE:LYE]
                [REAGENT:LYE_CONTAINER:1:NONE:NONE:NONE:NONE]
                    [CONTAINS:LYE]
                    [PRESERVE_REAGENT]
                    [DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
                [REAGENT:OIL:150:LIQUID_MISC:NONE:NONE:NONE]
                    [UNROTTEN]
                    [HAS_MATERIAL_REACTION_PRODUCT:SOAP_MAT]
                [REAGENT:OIL_CONTAINER:1:NONE:NONE:NONE:NONE]
                    [CONTAINS:OIL]
                    [PRESERVE_REAGENT]
                    [DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
                [PRODUCT:100:1:BAR:NONE:GET_MATERIAL_FROM_REAGENT:OIL:SOAP_MAT]
                    [PRODUCT_DIMENSION:150]
                [SKILL:SOAP_MAKING]

            [REACTION:MAKE_PEARLASH]
                [NAME:make pearlash]
                [BUILDING:KILN:CUSTOM_P]
                [REAGENT:A:150:BAR:NONE:POTASH:NONE]
                [PRODUCT:100:1:BAR:NONE:PEARLASH:NONE][PRODUCT_DIMENSION:150]
                [FUEL]
                [SKILL:SMELT]

            [REACTION:PROCESS_PLANT_TO_BAG]
                [NAME:process plant to bag]
                [BUILDING:FARMER:CUSTOM_B]
                [REAGENT:PLANT:1:PLANT:NONE:NONE:NONE]
                    [HAS_MATERIAL_REACTION_PRODUCT:BAG_ITEM]
                    [UNROTTEN]
                [REAGENT:BAG:1:BOX:NONE:NONE:NONE]
                    [EMPTY]
                    [BAG]
                    [PRESERVE_REAGENT]
                    [DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
                [PRODUCT:100:5:GET_ITEM_DATA_FROM_REAGENT:PLANT:BAG_ITEM]
                    [PRODUCT_TO_CONTAINER:BAG]
                [PRODUCT:100:1:SEEDS:NONE:GET_MATERIAL_FROM_REAGENT:PLANT:SEED_MAT]
                [SKILL:PROCESSPLANTS]

            [REACTION:TEST_DESCRIPTION]
                [DESCRIPTION:Make sure multi-line, empty values, and USE_TOOL is accepted]
                [DESCRIPTION:]
                [DESCRIPTION:USE_TOOL:EXAMPLE_TOOL]
            ",
        )
        .add_test_lexer_diagnostics_codes(vec![])
        .add_test_lexer_diagnostics_ranges(vec![]),
    )
    .add_test_structure(DFRaw {
        header: "reaction_other".to_owned(),
        token_structure: vec![ObjectToken {
            reaction_tokens: vec![
                ReactionToken {
                    reference: Some(ReferenceTo::new("TAN_A_HIDE".to_owned())),
                    name: Some("tan a hide".to_owned()),
                    automatic: Some(()),
                    building: vec![(
                        ReferenceTo::new("TANNER".to_owned()),
                        Choose::Choice1(KeyBindEnum::CustomT)
                    )],
                    skill: Some(SkillEnum::Tanner),
                    reagents: vec![ReagentToken {
                        reference: Some((
                            ReferenceTo::new("A".to_owned()),
                            1,
                            Choose::Choice1((NoneEnum::None, NoneEnum::None)),
                            Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                        )),
                        has_material_reaction_product: Some(Reference("TAN_MAT".to_owned())),
                        unrotten: Some(()),
                        use_body_component: Some(()),
                        ..Default::default()
                    }],
                    products: vec![ProductToken {
                        reference: Some((
                            100,
                            1,
                            Choose::Choice1((
                                ItemReferenceArg {
                                    item_type: Reference("SKIN_TANNED".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                },
                                Choose::Choice2(GetMaterialFromReagentArg((
                                    ReferenceTo::new("A".to_owned()),
                                    Choose::Choice2(ReferenceTo::new("TAN_MAT".to_owned())),
                                ))),
                            )),
                        )),
                        ..Default::default()
                    }],
                    ..Default::default()
                },
                ReactionToken {
                    reference: Some(ReferenceTo::new("RENDER_FAT".to_owned())),
                    name: Some("render fat".to_owned()),
                    automatic: Some(()),
                    building: vec![(
                        ReferenceTo::new("KITCHEN".to_owned()),
                        Choose::Choice1(KeyBindEnum::HotkeyKitchenRenderFat)
                    )],
                    skill: Some(SkillEnum::Cook),
                    reagents: vec![ReagentToken {
                        reference: Some((
                            ReferenceTo::new("A".to_owned()),
                            150,
                            Choose::Choice2(ItemReferenceArg {
                                item_type: Reference("GLOB".to_owned()),
                                item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                            }),
                            Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                        )),
                        has_material_reaction_product: Some(Reference("RENDER_MAT".to_owned())),
                        reaction_class: Some(Reference("FAT".to_owned())),
                        unrotten: Some(()),
                        ..Default::default()
                    }],
                    products: vec![ProductToken {
                        reference: Some((
                            100,
                            1,
                            Choose::Choice1((
                                ItemReferenceArg {
                                    item_type: Reference("GLOB".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                },
                                Choose::Choice2(GetMaterialFromReagentArg((
                                    ReferenceTo::new("A".to_owned()),
                                    Choose::Choice2(ReferenceTo::new("RENDER_MAT".to_owned())),
                                ))),
                            )),
                        )),
                        ..Default::default()
                    }],
                    ..Default::default()
                },
                ReactionToken {
                    reference: Some(ReferenceTo::new("MAKE_SOAP_FROM_TALLOW".to_owned())),
                    name: Some("make soap from tallow".to_owned()),
                    building: vec![(
                        ReferenceTo::new("SOAP_MAKER".to_owned()),
                        Choose::Choice1(KeyBindEnum::CustomT)
                    )],
                    attribute_ip: Some(20),
                    skill: Some(SkillEnum::SoapMaking),
                    skill_ip: Some(40),
                    skill_roll_range: Some((Clamp::new(11), 6)),
                    reagents: vec![
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("LYE".to_owned()),
                                150,
                                Choose::Choice2(ItemReferenceArg {
                                    item_type: Reference("LIQUID_MISC".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                }),
                                Choose::Choice1(MaterialTokenArg {
                                    material: MaterialTypeEnum::Lye(None),
                                }),
                            )),
                            ..Default::default()
                        },
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("LYE_CONTAINER".to_owned()),
                                1,
                                Choose::Choice1((NoneEnum::None, NoneEnum::None)),
                                Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                            )),
                            contains: Some(Reference("LYE".to_owned())),
                            does_not_determine_product_amount: Some(()),
                            preserve_reagent: Some(()),
                            ..Default::default()
                        },
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("TALLOW".to_owned()),
                                150,
                                Choose::Choice2(ItemReferenceArg {
                                    item_type: Reference("GLOB".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                }),
                                Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                            )),
                            has_material_reaction_product: Some(Reference(
                                "SOAP_MAT".to_owned()
                            )),
                            reaction_class: Some(Reference("TALLOW".to_owned())),
                            unrotten: Some(()),
                            ..Default::default()
                        }
                    ],
                    products: vec![ProductToken {
                        reference: Some((
                            100,
                            1,
                            Choose::Choice1((
                                ItemReferenceArg {
                                    item_type: Reference("BAR".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                },
                                Choose::Choice2(GetMaterialFromReagentArg((
                                    ReferenceTo::new("TALLOW".to_owned()),
                                    Choose::Choice2(ReferenceTo::new("SOAP_MAT".to_owned())),
                                ))),
                            )),
                        )),
                        product_dimension: Some(150),
                        ..Default::default()
                    }],
                    ..Default::default()
                },
                ReactionToken {
                    reference: Some(ReferenceTo::new("MAKE_SOAP_FROM_OIL".to_owned())),
                    name: Some("make soap from oil".to_owned()),
                    building: vec![(
                        ReferenceTo::new("SOAP_MAKER".to_owned()),
                        Choose::Choice1(KeyBindEnum::CustomO)
                    )],
                    skill: Some(SkillEnum::SoapMaking),
                    reagents: vec![
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("LYE".to_owned()),
                                150,
                                Choose::Choice2(ItemReferenceArg {
                                    item_type: Reference("LIQUID_MISC".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                }),
                                Choose::Choice1(MaterialTokenArg {
                                    material: MaterialTypeEnum::Lye(None),
                                }),
                            )),
                            ..Default::default()
                        },
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("LYE_CONTAINER".to_owned()),
                                1,
                                Choose::Choice1((NoneEnum::None, NoneEnum::None)),
                                Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                            )),
                            contains: Some(Reference("LYE".to_owned())),
                            does_not_determine_product_amount: Some(()),
                            preserve_reagent: Some(()),
                            ..Default::default()
                        },
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("OIL".to_owned()),
                                150,
                                Choose::Choice2(ItemReferenceArg {
                                    item_type: Reference("LIQUID_MISC".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                }),
                                Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                            )),
                            has_material_reaction_product: Some(Reference(
                                "SOAP_MAT".to_owned()
                            )),
                            unrotten: Some(()),
                            ..Default::default()
                        },
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("OIL_CONTAINER".to_owned()),
                                1,
                                Choose::Choice1((NoneEnum::None, NoneEnum::None)),
                                Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                            )),
                            contains: Some(Reference("OIL".to_owned())),
                            does_not_determine_product_amount: Some(()),
                            preserve_reagent: Some(()),
                            ..Default::default()
                        },
                    ],
                    products: vec![ProductToken {
                        reference: Some((
                            100,
                            1,
                            Choose::Choice1((
                                ItemReferenceArg {
                                    item_type: Reference("BAR".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                },
                                Choose::Choice2(GetMaterialFromReagentArg((
                                    ReferenceTo::new("OIL".to_owned()),
                                    Choose::Choice2(ReferenceTo::new("SOAP_MAT".to_owned())),
                                ))),
                            )),
                        )),
                        product_dimension: Some(150),
                        ..Default::default()
                    }],
                    ..Default::default()
                },
                ReactionToken {
                    reference: Some(ReferenceTo::new("MAKE_PEARLASH".to_owned())),
                    name: Some("make pearlash".to_owned()),
                    building: vec![(
                        ReferenceTo::new("KILN".to_owned()),
                        Choose::Choice1(KeyBindEnum::CustomP)
                    )],
                    fuel: Some(()),
                    skill: Some(SkillEnum::Smelt),
                    reagents: vec![ReagentToken {
                        reference: Some((
                            ReferenceTo::new("A".to_owned()),
                            150,
                            Choose::Choice2(ItemReferenceArg {
                                item_type: Reference("BAR".to_owned()),
                                item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                            }),
                            Choose::Choice1(MaterialTokenArg {
                                material: MaterialTypeEnum::Potash(Some(NoneEnum::None)),
                            }),
                        )),
                        ..Default::default()
                    }],
                    products: vec![ProductToken {
                        reference: Some((
                            100,
                            1,
                            Choose::Choice1((
                                ItemReferenceArg {
                                    item_type: Reference("BAR".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                },
                                Choose::Choice1(MaterialTokenArg {
                                    material: MaterialTypeEnum::Pearlash(Some(NoneEnum::None))
                                }),
                            )),
                        )),
                        product_dimension: Some(150),
                        ..Default::default()
                    }],
                    ..Default::default()
                },
                ReactionToken {
                    reference: Some(ReferenceTo::new("PROCESS_PLANT_TO_BAG".to_owned())),
                    name: Some("process plant to bag".to_owned()),
                    building: vec![(
                        ReferenceTo::new("FARMER".to_owned()),
                        Choose::Choice1(KeyBindEnum::CustomB)
                    )],
                    skill: Some(SkillEnum::Processplants),
                    reagents: vec![
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("PLANT".to_owned()),
                                1,
                                Choose::Choice2(ItemReferenceArg {
                                    item_type: Reference("PLANT".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                }),
                                Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                            )),
                            has_material_reaction_product: Some(Reference(
                                "BAG_ITEM".to_owned()
                            )),
                            unrotten: Some(()),
                            ..Default::default()
                        },
                        ReagentToken {
                            reference: Some((
                                ReferenceTo::new("BAG".to_owned()),
                                1,
                                Choose::Choice2(ItemReferenceArg {
                                    item_type: Reference("BOX".to_owned()),
                                    item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                }),
                                Choose::Choice2((NoneEnum::None, NoneEnum::None)),
                            )),
                            bag: Some(()),
                            does_not_determine_product_amount: Some(()),
                            empty: Some(()),
                            preserve_reagent: Some(()),
                            ..Default::default()
                        }
                    ],
                    products: vec![
                        ProductToken {
                            reference: Some((
                                100,
                                5,
                                Choose::Choice2((
                                    GetItemDataFromReagentEnum::GetItemDataFromReagent,
                                    ReferenceTo::new("PLANT".to_owned()),
                                    Choose::Choice2(Reference("BAG_ITEM".to_owned()))
                                )),
                            )),
                            product_to_container: Some(Reference("BAG".to_owned())),
                            ..Default::default()
                        },
                        ProductToken {
                            reference: Some((
                                100,
                                1,
                                Choose::Choice1((
                                    ItemReferenceArg {
                                        item_type: Reference("SEEDS".to_owned()),
                                        item_subtype: Choose::Choice1(NoSubtypeEnum::None),
                                    },
                                    Choose::Choice2(GetMaterialFromReagentArg((
                                        ReferenceTo::new("PLANT".to_owned()),
                                        Choose::Choice2(ReferenceTo::new("SEED_MAT".to_owned())),
                                    ))),
                                )),
                            )),
                            ..Default::default()
                        }
                    ],
                    ..Default::default()
                },
                ReactionToken {
                    reference: Some(ReferenceTo::new("TEST_DESCRIPTION".to_owned())),
                    description: vec![
                        AllowEmpty::Some(Choose::Choice2(
                            "Make sure multi-line, empty values, and USE_TOOL is accepted"
                                .to_owned()
                        )),
                        AllowEmpty::None,
                        AllowEmpty::Some(Choose::Choice1(
                            ReactionDescriptionUseItemTokenArg::UseTool(ReferenceTo::new(
                                "EXAMPLE_TOOL".to_owned()
                            ))
                        )),
                    ],
                    ..Default::default()
                },
            ],
            ..Default::default()
        }],
    })
    .add_test_syntax_diagnostics_codes(vec![])
    .add_test_syntax_diagnostics_ranges(vec![])
    .run_test();
}