Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine and distribute yang-lsp-settings-schema.json #238

Merged
merged 2 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
root = true

[*.json]
[*]
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true

[{*.json,yang.settings}]
indent_style = space
indent_size = 2

[*.md]
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2

[*.gradle]
indent_style = tab
indent_size = 4

[gradlew]
indent_style = space
indent_size = 4

[gradlew.bat]
end_of_line = crlf

[*.yml]
indent_style = space
indent_size = 2
10 changes: 10 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
"kind": "build",
"isDefault": true
}
},
{
"label": "Gradle Build Distribution",
"type": "shell",
"command": "cd yang-lsp && ./gradlew --no-daemon build copyDist",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": false
}
}
]
}
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# yang-lsp

[![GH Build Status](https://github.com/theia-ide/yang-lsp/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/theia-ide/yang-lsp/actions/workflows/main.yml)
[![GH Build Status](https://github.com/TypeFox/yang-lsp/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/TypeFox/yang-lsp/actions/workflows/main.yml)
[![Build status](https://ci.appveyor.com/api/projects/status/96eo9k5yo0wtpj50/branch/master?svg=true)](https://ci.appveyor.com/project/kittaakos/yang-lsp/branch/master)

A language server for YANG (see [Language Server Protocol](https://github.com/Microsoft/language-server-protocol)).
Expand All @@ -17,13 +17,13 @@ Both variants include start scripts to launch the background process. Connect it
The YANG Language Server is currently being used in

- [YANGSTER](https://github.com/theia-ide/yangster) based on [Theia](https://github.com/theia-ide/theia) (incl. diagram extension)
- [Yang VS Code](https://github.com/theia-ide/yang-vscode) available on the [VS Marketplace](https://marketplace.visualstudio.com/items?itemName=typefox.yang-vscode)
- [Yang VS Code](https://github.com/TypeFox/yang-vscode) available on the [VS Marketplace](https://marketplace.visualstudio.com/items?itemName=typefox.yang-vscode)
- [Yang Eclipse](https://github.com/theia-ide/yang-eclipse)

## Build

```shell
git clone https://github.com/theia-ide/yang-lsp.git
git clone https://github.com/TypeFox/yang-lsp.git
cd yang-lsp/yang-lsp
./gradlew build
```
Expand All @@ -33,10 +33,10 @@ The YANG Language Server is currently being used in
The yang-lsp is the base of multiple binaries

| Repository | Client | Binary | Bin Repo | CI | Trigger |
| ---------- | ------ | ------ | -------- | --- | ---------- |
| [yang-lsp](https://github.com/theia-ide/yangs-lsp) | LSP | JAR + script | GH Action Artifacts | [GH Action](https://github.com/theia-ide/yang-lsp/actions/workflows/main.yml) | GH Commit / PR |
| ---------- | ------ | ------ | -------- | --- | ------- |
| [yang-lsp](https://github.com/TypeFox/yangs-lsp) | LSP | JAR + script | GH Action Artifacts | [GH Action](https://github.com/TypeFox/yang-lsp/actions/workflows/main.yml) | GH Commit / PR |
| [yangster](https://github.com/theia-ide/yangster) | Theia Browser | Docker image | Docker Hub | [Docker Hub](https://hub.docker.com/r/typefox/yangster/builds) | GitHub hook / Jenkins pipeline|
| | Theia | Theia extension| npm | [Jenkins](http://services.typefox.io/open-source/jenkins/job/yangster/) | `yarn run publish` |
| [yangster-electron](https://github.com/theia-ide/yangster-electron) | Theia Electron | executables | ? | ? | ? |
| [yang-eclipse](https://github.com/theia-ide/yang-eclipse) | Eclipse | p2 update site | Eclipse Marketplace | [Jenkins](http://services.typefox.io/open-source/jenkins/job/yang-eclipse/) | GitHub hook / Jenkins pipeline |
| [yang-vscode](https://github.com/theia-ide/yang-vscode) | VSCode | VSCode extension | VSCode Marketplace | - | `vsce` |
| [yang-vscode](https://github.com/TypeFox/yang-vscode) | VSCode | VSCode extension | VSCode Marketplace | - | `vsce` |
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ build_script:
- ./yang-lsp/gradlew.bat -p yang-lsp build --refresh-dependencies --no-daemon

cache:
- C:\Users\appveyor\.gradle
- C:\Users\appveyor\.m2
- C:\Users\appveyor\.gradle
- C:\Users\appveyor\.m2
108 changes: 57 additions & 51 deletions docs/Extensions.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# Extensions

The yang-lsp allows to have additional third party extensions, configured through the [`yang.settings` file](Settings.md).
That file must be located in the root of an opened directory must conform to JSON syntax.
The yang-lsp allows to have additional third party extensions, configured through `yang.settings`.
For details on file format and schema see [Settings.md](./Settings.md).

So far two different kinds of extensions are supported :
- Validators (`IValidatorExtension`)
- Commands (`ICommandExtension`)

- Validators (`IValidatorExtension`)
- Commands (`ICommandExtension`)

## Create a Validator

A validator extension is a Java class that implements the interface `io.typefox.yang.validation.IValidatorExtension`.
A validator extension is a Java class that implements the interface `io.typefox.yang.validation.IValidatorExtension`.
Here is a small example:

```java
Expand All @@ -19,72 +20,77 @@ package my.pack;

public class MyExampleValidator implements IValidatorExtension {

public static final String BAD_NAME = "bad_name";
public static final String BAD_NAME = "bad_name";

@Override
public void validate(AbstractModule module, IAcceptor<Issue> issueAcceptor, CancelIndicator cancelIndicator) {
if (module.getName().equals("foo")) {
issueAcceptor.accept(IssueFactory.createIssue(module, YangPackage.Literals.ABSTRACT_MODULE__NAME, "'foo' is a bad name", BAD_NAME));
}
}
@Override
public void validate(AbstractModule module, IAcceptor<Issue> issueAcceptor, CancelIndicator cancelIndicator) {
if (module.getName().equals("foo")) {
issue = IssueFactory.createIssue(module, YangPackage.Literals.ABSTRACT_MODULE__NAME,
"'foo' is a bad name", BAD_NAME)
issueAcceptor.accept();
}
}

}
```
```

## Create a Command Extension

A command extension contributes actions, that will be shown in the context menu of a supporting client (currently only Yangster supports it).
A command extension contributes actions, that will be shown in the context menu
of a supporting client (currently only Yangster supports it).

Here is an example:

```xtend
```java
class MyCommand implements ICommandExtension {

static val COMMAND = "Create a file name 'foo.txt'."
/**
* return a list of commands. A command string is used as ID internally and as a label in the UI.
*/
override getCommands() {
#[COMMAND]
}
/**
* Called when the user asked to execute a certain command.
*/
override executeCommand(String command, Resource resource, LanguageClient client) {
if (COMMAND == command) {
// get the project directory
val uri = ProjectConfigAdapter.findInEmfObject(resource.resourceSet)?.projectConfig?.path.toFileString
val f = new File(uri, 'foo.txt')
if (f.exists) {
client.showMessage(new MessageParams => [
message = 'Such a file already exists.'
])
} else {
f.createNewFile
}
}
}
static val COMMAND = "Create a file name 'foo.txt'."

/**
* return a list of commands. A command string is used as ID internally and as a label in the UI.
*/
override getCommands() {
#[COMMAND]
}

/**
* Called when the user asked to execute a certain command.
*/
override executeCommand(String command, Resource resource, LanguageClient client) {
if (COMMAND == command) {
// get the project directory
val uri = ProjectConfigAdapter.findInEmfObject(resource.resourceSet)?.projectConfig?.path.toFileString
val f = new File(uri, 'foo.txt')
if (f.exists) {
client.showMessage(new MessageParams => [
message = 'Such a file already exists.'
])
} else {
f.createNewFile
}
}
}

}
```


## Package an extension

The class needs to be packaged in a jar. So simply use the java build tool of your preference to create a jar from it. Put the jar somewhere relative to the project's root directory.
The class needs to be packaged in a jar. So simply use the java build tool of
your preference to create a jar from it. Put the jar somewhere relative to the
project's root directory.

## Add the plugin

Create (or open) the `yang.settings` file and add the plugin using the following configuration:
Create (or open) the `yang.settings` file and add the plugin using the following
configuration:

```json
"extension" : {
"classpath" : "extension.jar",
"validators" : "my.pack.MyExampleValidator",
"commands" : "my.pack.MyCommand"
}
"extension" : {
"classpath" : "extension.jar",
"validators" : "my.pack.MyExampleValidator",
"commands" : "my.pack.MyCommand"
}
```

The language server will automatically pick up the extension.

105 changes: 53 additions & 52 deletions docs/Processing_Files.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Processing YANG files
# Processing YANG files

As yang-lsp contains all the tools to parse, link and validate YANG models. If you want to further process the YANG files you authored with yang-lsp it makes sense to make reuse of the existing functionality.

Here is some example code in Xtend for an application that reads in all YANG files from a given directory. The files are parsed into our YANG EMF model, all cross-references are resolved and all files are validated. If there are no errors, the method `generate()` is called for all resources:

```Xtend
```xtend
package io.typefox.yang.example

import com.google.inject.Inject
Expand All @@ -20,66 +20,67 @@ import org.eclipse.xtext.util.CancelIndicator
import org.eclipse.xtext.validation.CheckMode
import org.eclipse.xtext.validation.IResourceValidator

class StandaloneExample {

def static void main(String... args) {
val injector = new YangStandaloneSetup().createInjectorAndDoEMFRegistration
injector.getInstance(StandaloneExample).run(args)
}

@Inject XtextResourceSet resourceSet
@Inject IResourceValidator validator
boolean hasErrors = false

def void run(String... args) {
addFile(new File(args.head))
resourceSet.resources.forEach [ resource |
EcoreUtil.resolveAll(resource)
val issues = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl)
issues.forEach [ issue |
hasErrors = hasErrors || issue.severity === Severity.ERROR
System.err.println(issue)
]
]
if(!hasErrors) {
resourceSet.resources.forEach [
generate
]
}
}
def void addFile(File file) {
if(file.isDirectory)
file.listFiles.forEach[ addFile ]
else if(file.name.endsWith('.yang'))
resourceSet.getResource(URI.createURI(file.toURI.toString), true)
}

def generate(Resource resource) {
// do your own processing here
resource.allContents.filter(Module).forEach [ module |
println('''
Found module «module.name»
''')
]
}
class StandaloneExample {

def static void main(String... args) {
val injector = new YangStandaloneSetup().createInjectorAndDoEMFRegistration
injector.getInstance(StandaloneExample).run(args)
}

@Inject XtextResourceSet resourceSet
@Inject IResourceValidator validator
boolean hasErrors = false

def void run(String... args) {
addFile(new File(args.head))
resourceSet.resources.forEach [ resource |
EcoreUtil.resolveAll(resource)
val issues = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl)
issues.forEach [ issue |
hasErrors = hasErrors || issue.severity === Severity.ERROR
System.err.println(issue)
]
]
if(!hasErrors) {
resourceSet.resources.forEach [
generate
]
}
}

def void addFile(File file) {
if(file.isDirectory)
file.listFiles.forEach[ addFile ]
else if(file.name.endsWith('.yang'))
resourceSet.getResource(URI.createURI(file.toURI.toString), true)
}

def generate(Resource resource) {
// do your own processing here
resource.allContents.filter(Module).forEach [ module |
println('''
Found module «module.name»
''')
]
}
}
```
A number of useful helper methods can be found in the [utils package](https://github.com/theia-ide/yang-lsp/tree/master/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/utils)

A number of useful helper methods can be found in the [utils package](https://github.com/TypeFox/yang-lsp/tree/master/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/utils)

Here is sample `build.gradle` to build the above class:

```groovy
buildscript {
repositories.jcenter()
dependencies {
classpath 'org.xtext:xtext-gradle-plugin:1.0.19'
}
repositories.jcenter()
dependencies {
classpath 'org.xtext:xtext-gradle-plugin:1.0.19'
}
}

repositories {
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
}

apply plugin: 'org.xtext.xtend'
Expand All @@ -90,7 +91,7 @@ apply plugin: 'maven'
group = 'io.typefox.yang'
version = '0.1.0-SNAPSHOT'

dependencies {
dependencies {
compile 'io.typefox.yang:io.typefox.yang:0.1.0-SNAPSHOT'
compile 'org.eclipse.xtext:org.eclipse.xtext:2.13.0'
compile 'org.eclipse.xtend:org.eclipse.xtend.lib:2.13.0'
Expand Down
Loading
Loading