Skip to content

Commit

Permalink
♿ Add template
Browse files Browse the repository at this point in the history
  • Loading branch information
Freed-Wu committed Mar 7, 2024
1 parent a68f08b commit bfe0a56
Show file tree
Hide file tree
Showing 40 changed files with 2,447 additions and 2 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
exclude: (^templates/.*|.*\.json$)
exclude: ^template(s)?/

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand All @@ -23,7 +23,7 @@ repos:
- id: check-toml
- id: check-json
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.4
rev: v1.5.5
hooks:
- id: remove-crlf
- repo: https://github.com/codespell-project/codespell
Expand Down
169 changes: 169 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,177 @@ mutt-language-server --generate-schema neomuttrc

![hover](https://github.com/neomutt/lsp-tree-sitter/assets/32936898/22a0347e-3d4f-45c5-833b-e89225ce3b74)

## Template

This project provides a template for
[copier](https://github.com/copier-org/copier).

For example, you want to create a language server for a filetype named
[`zathurarc`](https://pwmt.org/projects/zathura/documentation/). Please follow
the following steps:

### Create a tree-sitter parser

1. Create a tree-sitter-parser from [template](https://github.com/tree-sitter-grammars/template).
2. Publish it to PYPI

You can see if
[py-tree-sitter-languages](https://github.com/grantjenks/py-tree-sitter-languages)
supports the language where you want to create a language server.

### Copy a template

```sh
$ copier copy gh:neomutt/lsp-tree-sitter /path/to/your/XXX-language-server
🎤 What is your language name?
zathurarc
🎤 What is your file patterns? split by " "
*.zathurarc zathurarc
🎤 What is your project name?
zathura-language-server
🎤 What is your Python module name?
zathura_language_server
🎤 What is your Python class name?
ZathuraLanguageServer
🎤 What is your tree-sitter parser name?
tree-sitter-zathurarc
🎤 What is your user name?
wzy

Copying from template version None
create .
...
$ cd /path/to/your/XXX-language-server
$ tree .
.
├──  docs # documents
│ ├──  api
│ │ └──  zathura-language-server.md
│ ├──  conf.py
│ ├──  index.md
│ ├──  requirements.txt
│ └──  resources
│ ├──  configure.md
│ ├──  install.md
│ └──  requirements.md
├──  LICENSE
├──  pyproject.toml
├──  README.md
├──  requirements # optional dependencies
│ ├──  colorize.txt
│ ├──  dev.txt
│ └──  misc.txt
├──  requirements.txt
├──  src
│ └──  zathura_language_server
│ ├──  __init__.py
│ ├──  __main__.py
│ ├──  _shtab.py
│ ├──  assets
│ │ ├──  json # json schemas generated by misc/XXX.py
│ │ │ └──  zathurarc.json
│ │ └──  queries # tree-sitter queries
│ │ └──  import.scm
│ ├──  finders.py # project specific finders
│ ├──  misc
│ │ ├──  __init__.py
│ │ └──  zathurarc.py
│ ├──  py.typed
│ ├──  schema.py # project specific schemas
│ ├──  server.py # main file for server
│ └──  utils.py
├──  templates
│ ├──  class.txt
│ ├──  def.txt
│ ├──  metainfo.py.j2
│ └──  noarg.txt
└──  tests
└──  test_utils.py
```

1. Edit `schema.py` to convert a tree-sitter's tree to a json, which is the
core function of `XXX-langauge-server --convert`
2. Edit a `misc/XXX.py` to generate json schemas, which is the core function of
`XXX-languageserver --generate-schema`
3. Edit `server.py` to make sure the LSP features can work for specific
tree-sitter parsers.
4. Edit `queries/XXX.scm` to make sure the LSP features can work for specific
tree-sitter parsers if you use them.
5. Edit `finders.py` to add the language specific finders for
`XXX-languageserver --check` and `XXX-languageserver --format`

### Test if it can work

```sh
$ git init
$ pip install -e .
$ which zathura-language-server
~/.local/bin/zathura-language-server
```

1. Refer `docs/resources/configure.md` to configure your language server for
your editor.
2. Refer `README.md` to see the LSP features provided by your language server.

```sh
vi /path/to/zathurarc
```

You can test the LSP features.

Refer <https://docs.readthedocs.io> to see how to publish the documents.

## References

These following language servers can be a good example for beginners:

### [zathura-language-server](https://github.com/Freed-Wu/zathura-language-server)

`zathurarc`'s syntax only has 4 directives:

- `set option value`
- `include /the/path`
- `map key function`
- `unmap key`

Very few directives make creating
[tree-sitter-zathurarc](https://github.com/Freed-Wu/tree-sitter-zathurarc) and
editing `schema.py` very easy. So I am highly recommended starting from it.

### [tmux-language-server](https://github.com/Freed-Wu/tmux-language-server)

`tmux.conf` is more complex than `zathurarc`. It has not only
`set option = value` and `source /the/path`, but also 170+ other directives.

### [mutt-language-server](https://github.com/neomutt/mutt-language-server)

`muttrc` or `neomuttrc` has the following directives:

- `set option = value`
- `source /the/path`
- 80+ other directives

However, its `set` syntax is very flexible. The following syntaxes are legal:

- `set option2 = value1 option2 = value2 ...`
- `set option`: a shortcut for `set option = yes`
- `set nooption`: a shortcut for `set option = no`
- `set invoption`
- `set nooption1 invoption2 option3 ...`
- ...

So, in fact it is harder than `tmux.conf`, IMO.

### [termux-language-server](https://github.com/termux/termux-language-server)

`build.sh`, `PKGBUILD`, `*.ebuild` use same syntax of bash. However, they use
different json schemas. If the language where you want to create a language
server, you can refer it to know how to handle this situation.

### Other references

Some useful URLs for beginners who want to develop language servers:

- some [Chinese blogs](https://freed-wu.github.io/tag/lsp/) about how I write
these language servers
- [tree-sitter](https://tree-sitter.github.io/tree-sitter/)
Expand Down
37 changes: 37 additions & 0 deletions copier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
_templates_suffix: ""
_answers_file: .copier-answers.yml
_subdirectory: template

language:
type: str
help: What is your language name?

patterns:
type: str
help: What is your file patterns? split by " "
default: "*.{{ language }}"

project:
type: str
help: What is your project name?
default: "{{ language }}-language-server"

module:
type: str
help: What is your Python module name?
default: "{{ project | replace('-', '_') }}"

class:
type: str
help: What is your Python class name?
default: "{{ module | replace('_', ' ') | title | replace(' ', '') }}"

parser:
type: str
help: What is your tree-sitter parser name?
default: "tree-sitter-{{ language }}"

user:
type: str
help: What is your user name?
109 changes: 109 additions & 0 deletions template/.github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
"on":
push:
paths-ignore:
- "**.md"
- docs/*
pull_request:
paths-ignore:
- "**.md"
- docs/*
workflow_dispatch:

# https://github.com/softprops/action-gh-release/issues/236
permissions:
contents: write

env:
PYTHONUTF8: "1"
python-version: 3.x
cache: pip

jobs:
test:
strategy:
fail-fast: false
matrix:
runs-on:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: $\{\{matrix.runs-on\}\}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: $\{\{env.python-version\}\}
cache: $\{\{env.cache\}\}
cache-dependency-path: |-
requirements.txt
requirements/dev.txt
- name: Install dependencies
run: |
pip install -e '.[dev]'
- name: Test
run: |
pytest --cov
- uses: codecov/codecov-action@v3
build:
needs: test
strategy:
fail-fast: false
matrix:
runs-on:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: $\{\{matrix.runs-on\}\}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: $\{\{env.python-version\}\}
cache: $\{\{env.cache\}\}
cache-dependency-path: |-
requirements.txt
requirements/dev.txt
- name: Install dependencies
run: |
pip install build
- name: Build
run: |
pyproject-build
- uses: pypa/gh-action-pypi-publish@release/v1
if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/')
with:
password: $\{\{secrets.PYPI_API_TOKEN\}\}
- uses: actions/upload-artifact@v3
if: runner.os == 'Linux' && ! startsWith(github.ref, 'refs/tags/')
with:
path: |
dist/*
- uses: softprops/action-gh-release@v1
if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/')
with:
# body_path: build/CHANGELOG.md
files: |
dist/*
deploy-aur:
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: {{ user }}/update-aur-package@v1.0.11
with:
package_name: {{ project }}
ssh_private_key: $\{\{secrets.AUR_SSH_PRIVATE_KEY\}\}

deploy-nur:
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Trigger Workflow
run: >
curl -X POST -d '{"ref": "main"}'
-H "Accept: application/vnd.github.v3+json"
-H "Authorization: Bearer $\{\{secrets.GH_TOKEN\}\}"
https://api.github.com/repos/{{ user }}/nur-packages/actions/workflows/version.yml/dispatches
Loading

0 comments on commit bfe0a56

Please sign in to comment.