IDE Extension
IDE features, like syntax highlighting, error checking, auto-completion and interactive documentation could significantly increase productivity when writing naninovel scripts. We've made an extension for a free and open-source Visual Studio Code (available for Windows, MacOS and Linux) IDE, which provides the essential IDE support for NaniScript syntax.
Setup
Install VS Code Extension
- Open extensions window in VS Code via
View -> Extensions
menu - Search for "Naninovel" and click "Install" button
NOTE
Extension in the VS Code registry is compatible with the current stable Naninovel release. When using a preview release of Naninovel, switch to the pre-release extension stream. When using a final Naninovel release, disable auto-update in VS Code and install associated legacy version of the extension.
Activate the Extension
- Make sure Naninovel is installed in the Unity project
- Open the Unity project folder in VS Code
When the extension detects a .nani
file in the current workspace, it'll activate the bridging service, which handles the useful tasks, such as diagnosing the scripts, providing auto-completion, indicating which script line is currently played, etc.
Project Root
By default, Naninovel will generate a .nani
folder under the Unity project root, where it'll store the project metadata and bridging files required for communication with the authoring tools, such as the VS Code extension. This means, that when opening Naninovel projects with the VS Code, you have to select the folder containing the entire Unity project.
In case you'd like to open just the folder with the scenario scripts or another folder under the Unity project directory, select that folder via Naninovel Project Root
option in the engine configuration menu.
When selected, Naninovel will generate the metadata and bridging files under the custom folder, which you can then open with the VS Code as well.
Scenario Root
The VS Code extension has to be aware where the Naninovel scenario scripts (.nani
files) are stored, relative to the workspace root. By default, it expects them under Assets/Scenario
directory:
— in case you've changed the default in the Unity project configuration and using another directory to store the scrips, change the setting and restart VS Code; otherwise script paths won't be correctly resolved, resulting in navigation warnings and wrong paths shown in auto-completions.
VS Code Settings
Below is the recommended settings for VS Code to ignore Unity's autogenerated meta files, enable semantic syntax highlighting, word wrap and spell checking (given spell check extension is installed) and disable word-based suggestions (so that they don't constantly pop up when you type generic text lines):
{
"files.exclude": {
"**/*.meta": true
},
"editor.wordWrap": "on",
"editor.wordBasedSuggestions": "off",
"editor.occurrencesHighlight": "off",
"editor.suggest.showWords": false,
"editor.bracketPairColorization.enabled": false,
"editor.semanticTokenColorCustomizations": {
"enabled": true,
"rules": {
"CommentLine": { "foreground": "#5d6470", "italic": true },
"CommentText": { "foreground": "#5d6470", "italic": true },
"LabelLine": "#9bc37c",
"LabelText": "#9bc37c",
"CommandLine": "#6cb2ed",
"InlinedCommand": "#6cb2ed",
"Command": "#6cb2ed",
"CommandIdentifier": "#6cb2ed",
"Parameter": "#cd9769",
"ParameterIdentifier": "#cd9769",
"ParameterValue": "#e2be7f",
"LocalizableValue": "#acb2be",
"GenericTextLine": "#acb2be",
"GenericTextPrefix": "#e2be7f",
"GenericTextAuthor": "#e2be7f",
"GenericTextAuthorAppearance": "#e2be7f",
"Expression": "#62b8c1",
"TextIdentifier": "#5d6470",
"WaitFlag": "#6cb2ed",
"Error": "#d14e4e"
}
},
"cSpell.enableFiletypes": [
"naniscript"
]
}
You can access the settings JSON file via File -> Preference -> Settings
menu and clicking "Open Settings (JSON)" button in the upper-right corner of the window. Select "User" tab to edit settings for all projects or "Workspace" to affect only the current project with the naninovel scripts.
Feel free to customize the settings as you see fit.
Spell Check
To enable spell checking in the naninovel scripts, install a spell checker extension, eg. Code Spell Check and turn on the checking for naniscript
language; see the settings section below for an example on how to enable naniscript language for the Code Spell Check extension.
Folding
Following artifacts get folding support by default:
- Labels, until other label
- Joint comment lines
- Indented (nested) blocks
It's also possible to specify custom folding regions via comments with special syntax:
- Open with
; > region name
, where "region name" can be anything - Close with
; < region name
, where "region name" equals the opening name
Project Metadata
The Naninovel metadata is a JSON file, which contains various information associated with the authored project: available characters, backgrounds, resources, commands, etc. This information is used by the authoring tools, such as the IDE extension and web editor to provide the helpful functions, such as auto-completion and diagnostics.
The metadata file is stored at .nani/Metadata.json
, under the Unity project root. When Auto Generate Metadata
is enabled under engine configuration, the metadata is re-generated automatically when editor starts and after compiling C# scripts. To manually initiate metadata update, either use Naninovel -> Update Metadata
editor menu or Ctrl + Shift + U
hotkey.
Metadata Provider
To fill generated metadata with additional custom values or override defaults, create a C# class and implement IMetadataProvider
interface; the implementation is expected to have a parameterless constructor. When found, custom provider will be used instead of the default one each time project metadata is generated (eg, when syncing with an IDE extension).
Below is the default metadata provider, which you can use as reference when implementing your own:
public class DefaultMetadataProvider : IMetadataProvider
{
public Project GetMetadata ()
{
var meta = new Project();
var cfg = ProjectConfigurationProvider.LoadOrDefault<ScriptsConfiguration>();
meta.EntryScript = cfg.StartGameScript;
meta.TitleScript = cfg.TitleScript;
Notify("Processing commands...", 0);
meta.Commands = MetadataGenerator.GenerateCommandsMetadata();
Notify("Processing resources...", .25f);
meta.Resources = MetadataGenerator.GenerateResourcesMetadata();
Notify("Processing actors...", .50f);
meta.Actors = MetadataGenerator.GenerateActorsMetadata();
Notify("Processing variables...", .75f);
meta.Variables = MetadataGenerator.GenerateVariablesMetadata();
Notify("Processing functions...", .95f);
meta.Functions = MetadataGenerator.GenerateFunctionsMetadata();
Notify("Processing constants...", .99f);
meta.Constants = MetadataGenerator.GenerateConstantsMetadata();
meta.Syntax = Compiler.Syntax;
return meta;
}
private static void Notify (string info, float progress)
{
if (EditorUtility.DisplayCancelableProgressBar("Generating Metadata", info, progress))
throw new OperationCanceledException("Metadata generation cancelled by the user.");
}
}
IDE Attributes
Naninovel has a number of C# attributes to provide various IDE-related functionality to custom commands and expression functions. For example, to add on-hover documentation to the custom commands and/or parameters, apply Doc
attribute to command type and parameter fields respectively:
[Doc("Summary of the custom command.")]
public class CustomCommand : Command
{
[Doc("Summary of the custom parameter.")]
public StringParameter CustomParameter;
}
To make a parameter auto-complete with both built-in and custom expression functions and pre-defined custom variables use ExpressionContext
attribute.
[ExpressionContext]
public StringParameter Expression;
To auto-complete with values from an arbitrary enumeration type use ConstantContext
attribute.
[ConstantContext(typeof(PlatformID))]
public StringParameter Platform;
To auto-complete and analyze usage and correctness of navigation endpoints (script path and label) use EndpointContext
attribute.
[EndpointContext]
public NamedStringParameter Goto;
To auto-complete with a resource use ResourceContext
and provide path prefix of the resources. Below example will complete with audio resources:
[ResourceContext(AudioConfiguration.DefaultAudioPathPrefix)]
public StringParameter Audio;
To auto-complete with an actor ID (of any type) use ActorContext
attribute.
[ActorContext]
public StringParameter ActorId;
To auto-complete with an actor ID of specific type use ActorContext
attribute with first argument specifying path prefix of the actor resources. Below will complete with printer IDs:
[ActorContext(TextPrintersConfiguration.DefaultPathPrefix)]
public StringParameter PrinterId;
To auto-complete appearances of an actor with ID specified in the same named or another parameter in the current command, use AppearanceContext
attribute. Be aware, that this requires ActorContext
attribute specified in the same command.
[ActorContext(CharactersConfiguration.DefaultPathPrefix)]
public StringParameter CharacterId;
[AppearanceContext]
public StringParameter CharacterAppearance;
Notice, that each of the above attributes allows providing an optional namedIndex
argument. Use it with named parameters to specify for which part of the parameter value the attribute belongs. Below example will allow auto-completing name part of the named parameter with character IDs and value part with appearances for the currently typed character (similar to nameless parameter of @char
command).
[ActorContext(CharactersConfiguration.DefaultPathPrefix, 0), AppearanceContext(1)]
public NamedStringParameter IdAndAppearance;
The parameter context attributes can be applied to class instead of fields to allow specifying (or overriding) the contexts for the fields declared in parent classes. For example, while Id
parameter is declared in the abstract ModifyActor
command, the context is applied to ModifyBackground
inherited class:
[ActorContext(BackgroundsConfiguration.DefaultPathPrefix, paramId: "Id")]
public class ModifyBackground : ModifyActor { }
You can repurpose the same tactic when inheriting custom commands from the built-in ones. Don't forget to provide the optional paramId
argument when applying parameter context attribute to a class instead of field.
TIP
Most of the same parameter context attributes can be applied to expression function parameters to make them auto-complete and diagnosed by the IDE extension. Find an example in the functions guide.
Constant Expressions
When using ConstantContext
IDE Attribute, instead of enum it's possible to specify an expression to be evaluated by the IDE to produce a constant name based on command parameter values or other variables, such as currently inspected script.
Expression syntax:
- Evaluated parts should be wrapped in curly braces (
{}
) - To reference currently inspected script path, use
$Script
- To reference parameter value, use
:
followed by the parameter ID (field name as specified in C#, not alias) - Use
[0]
or[1]
after parameter reference to specify named value (0 for name and 1 for index) - Use null coalescing (
??
) after parameter reference for fallback in case the value is not specified - Use concatenation operator (
+
) to merge values from multiple constants
For example, check the expression assigned to Path
parameter of the built-in [@goto]
command:
[ConstantContext("Labels/{:Path[0]??$Script}", 1)]
public NamedStringParameter Path;
— when name component of the parameter is assigned with foo
, it will evaluate to Labels/foo
, otherwise, given inspected script path is bar
it will evaluate to Labels/bar
.
Another example for character poses applied to @char
command:
[ConstantContext("Poses/Characters/{:Id??:IdAndAppearance[0]}+Poses/Characters/*", paramId: nameof(Pose))]
public class ModifyCharacter { ... }
— will merge shared character poses with poses for characters with ID assigned to "ID" parameter or (when not assigned) name component of "IdAndAppearance" parameter.
Constant expressions combined with custom metadata providers allow creating arbitrary autocompletion scenarios for the IDE extension.
Other IDEs and Editors
While we don't maintain extensions for other editors, we have an open-sourced language server for Naninovel: github.com/naninovel/language. It's written in C#, but has JavaScript bindings and can be used in most modern IDEs. The implementation covers syntax highlighting, autocompletion, errors checking, etc. VS Code extension (which is built upon the language server) is open-sourced as well: github.com/naninovel/vscode.
Alternatively, in case you're using an editor with TextMate grammar support (eg, Sublime or Visual Studio), we have one ready: textmate.json.