Skip to content

Commit

Permalink
feat: simple ds.toml completion
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsDeltin committed May 23, 2024
1 parent 0bfb1b8 commit fc77699
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Deltin.Deltinteger.Parse;
using ICompletionHandler = OmniSharp.Extensions.LanguageServer.Protocol.Document.ICompletionHandler;
using CompletionList = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionList;
using CompletionItem = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionItem;
using CompletionParams = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionParams;
using CompletionRegistrationOptions = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionRegistrationOptions;
using Container = OmniSharp.Extensions.LanguageServer.Protocol.Models.Container<string>;
using CompletionCapability = OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities.CompletionCapability;
using Deltin.Deltinteger.Parse.Settings;

namespace Deltin.Deltinteger.LanguageServer
{
Expand All @@ -26,6 +24,10 @@ public CompletionHandler(OstwLangServer languageServer)

public async Task<CompletionList> Handle(CompletionParams completionParams, CancellationToken token)
{
// ds.toml completion
if (System.IO.Path.GetFileName(completionParams.TextDocument.Uri.Path) is "ds.toml" or "ostw.toml")
return DsTomlSettings.SettingsCompletionList;

var compilation = await _languageServer.ProjectUpdater.GetProjectCompilationAsync();

// If the script has not been parsed yet, return the default completion.
Expand Down Expand Up @@ -78,7 +80,7 @@ public CompletionRegistrationOptions GetRegistrationOptions(CompletionCapability
{
return new CompletionRegistrationOptions()
{
DocumentSelector = OstwLangServer.DocumentSelector,
DocumentSelector = OstwLangServer.CompletionDocumentSelector,
// Most tools trigger completion request automatically without explicitly requesting
// it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user
// starts to type an identifier. For example if the user types `c` in a JavaScript file
Expand Down
52 changes: 31 additions & 21 deletions Deltinteger/Deltinteger/Language Server/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,27 +277,37 @@ class DecompileFileArgs
public string File { get; set; }
}

public static readonly DocumentSelector DocumentSelector = new DocumentSelector(
new DocumentFilter()
{
Language = "ostw",
Pattern = "**/*.del"
},
new DocumentFilter()
{
Language = "ostw",
Pattern = "**/*.ostw"
},
new DocumentFilter()
{
Language = "ostw",
Pattern = "**/*.workshop"
},
new DocumentFilter()
{
Language = "ostw",
Pattern = "ds.toml"
}
static readonly DocumentFilter DelDocumentFilter = new()
{
Language = "ostw",
Pattern = "**/*.del"
};
static readonly DocumentFilter OstwDocumentFilter = new()
{
Language = "ostw",
Pattern = "**/*.ostw"
};
static readonly DocumentFilter WorkshopDocumentFilter = new()
{
Language = "ostw",
Pattern = "**/*.workshop"
};
static readonly DocumentFilter DsTomlDocumentFilter = new()
{
Language = "toml",
Pattern = "**/ds.toml"
};

public static readonly DocumentSelector DocumentSelector = new(
DelDocumentFilter,
OstwDocumentFilter,
WorkshopDocumentFilter
);
public static readonly DocumentSelector CompletionDocumentSelector = new(
DelDocumentFilter,
OstwDocumentFilter,
WorkshopDocumentFilter,
DsTomlDocumentFilter
);
}

Expand Down
10 changes: 10 additions & 0 deletions Deltinteger/Deltinteger/Model/StandardExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ public static bool TryGetValue<T>(this IEnumerable<T> enumerable, Func<T, bool>
return default;
}

public static IEnumerable<U> SelectWithoutNull<T, U>(this IEnumerable<T> enumerable, Func<T, U?> selector) where T : class
{
foreach (var item in enumerable)
{
var selected = selector(item);
if (selected is not null)
yield return selected;
}
}

public static T? Or<T>(this T? maybe, T? otherwise)
{
return maybe is not null ? maybe : otherwise;
Expand Down
72 changes: 70 additions & 2 deletions Deltinteger/Deltinteger/Parse/Settings.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
#nullable enable

using System.Text.Json.Serialization;
using CompletionList = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionList;
using CompletionItem = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionItem;
using CompletionItemKind = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionItemKind;
using System.Reflection;
using Deltin.Deltinteger.Model;

namespace Deltin.Deltinteger.Parse.Settings
{
public class DsTomlSettings
{
[JsonPropertyName("entry_point")]
public string EntryPoint { get; set; } = null;
public string? EntryPoint { get; set; } = null;

[JsonPropertyName("reset_nonpersistent")]
public bool ResetNonpersistent { get; set; } = false;
Expand Down Expand Up @@ -38,7 +45,7 @@ public class DsTomlSettings
public bool CompileMiscellaneousComments { get; set; } = true;

[JsonPropertyName("out_file")]
public string OutFile { get; set; } = null;
public string? OutFile { get; set; } = null;

[JsonPropertyName("variable_template")]
public bool VariableTemplate { get; set; } = false;
Expand All @@ -53,6 +60,67 @@ public class DsTomlSettings
public bool SubroutineStacksAreExtended { get; set; } = false;

public static readonly DsTomlSettings Default = new DsTomlSettings();

public static readonly CompletionList SettingsCompletionList = GetCompletionList();

static CompletionList GetCompletionList()
{
var properties = typeof(DsTomlSettings).GetProperties(BindingFlags.Public | BindingFlags.Instance).SelectWithoutNull(prop =>
{
// Find property name.
var jsonPropertyName = prop.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name;
if (jsonPropertyName is null)
return null;

// Determine default value.
var defaultValue = prop.GetValue(Default) switch
{
true => "true",
false => "false",
null => "null",
ReferenceValidationType.Inline => "inline",
ReferenceValidationType.Subroutine => "subroutine",
_ => string.Empty,
};
string insertText = $"{jsonPropertyName} = {defaultValue}";

return new CompletionItem()
{
Label = jsonPropertyName,
Detail = new MarkupBuilder().StartCodeLine().Add(insertText).EndCodeLine(),
Documentation = GetDocumentation(jsonPropertyName),
Kind = CompletionItemKind.Field,
InsertText = insertText
};
});
return new(properties);
}

static MarkupBuilder? GetDocumentation(string setting) => setting switch
{
"entry_point" => "The main OSTW file to begin analysis and compilation.",
"reset_nonpersistent" => new MarkupBuilder("If true, OSTW will not assume that all variables are zero by default.")
.NewLine().Add("This can be used to save & load games by copying the current global variable set as actions.")
.NewLine().Add("Any variable with the ").Code("persist").Add(" attribute will not be reset. Add the ").Code("persist").Add(" attribute to any variable you want part of your save state."),
"paste_check_is_extended" => new MarkupBuilder("Determines if the extra variable generated from reset_nonpersistent is placed in the extended collection."),
"log_delete_reference_zero" => new MarkupBuilder("If true, logs to inspector when an invalid class reference is used with the ").Code("delete").Add(" statement."),
"track_class_generations" => new MarkupBuilder("Improves class references so that every type of invalid pointer can be detected at runtime. This will increase element count a little."),
"global_reference_validation" => new MarkupBuilder("Checks class pointers when they are accessed. If the reference is invalid, the file and line of the OSTW code is logged to the inspector and the rule is aborted.")
.NewLine().Add("By default this will only detect null or 0 references, but with ").Code("track_class_generations").Add(" enabled it will detect any type of invalid pointer.")
.NewLine().Add("Increases element count by a lot."),
"reference_validation_type" => "Determines if the code generated by global_reference_validation is placed inline at every check or in a shared subroutine. Subroutine variant reduces element count from validation by 30%.",
"new_class_register_optimization" => new MarkupBuilder("Code like ").Code("a = new MyClass()").Add(" will be optimized so that the 'a' value which is already being overridden is used to assign to the heap, rather than creating a new register."),
"abort_on_error" => new MarkupBuilder("If an invalid class reference is found when ").Code("global_reference_validation").Add(" is enabled, this determines if the rule should be aborted."),
"c_style_workshop_output" => new MarkupBuilder("Controls the workshop output format.")
.NewLine().Add("Classic style (false):").NewLine().StartCodeLine().Add("Set Global Variable(A, Value In Array(Global Variable(B), 2));").EndCodeLine()
.NewLine().Add("C style (true):").NewLine().StartCodeLine().Add("Global.A = Global.B[2];").EndCodeLine(),
"compile_miscellaneous_comments" => "Toggles the extra comments generated by the OSTW compiler in the workshop output, like rule action count and extended collection names.",
"out_file" => "The file to write the generated workshop code to.",
"optimize_output" => "Controls if OSTW will optimize the generated workshop code.",
"use_tabs_in_workshop_output" => "Uses tabs instead of spaces in the generated workshop code.",
"subroutine_stacks_are_extended" => "Determines if the register used to store the object reference in class subroutine methods will be extended.",
"variable_template" or _ => null,
};
}

public enum ReferenceValidationType
Expand Down

0 comments on commit fc77699

Please sign in to comment.