mirror of
https://github.com/godotengine/emacs-gdscript-mode.git
synced 2025-12-31 21:48:34 +03:00
Compare commits
62 Commits
1.4.0
...
jcs090218-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a89ae451d9 | ||
|
|
32086df833 | ||
|
|
4ae8760e19 | ||
|
|
ab6aae89aa | ||
|
|
2737f1c68c | ||
|
|
cd92e12084 | ||
|
|
becce1a4ba | ||
|
|
718267511f | ||
|
|
d25f778f02 | ||
|
|
b8a840448a | ||
|
|
e0a8dc9f0b | ||
|
|
8a28276daa | ||
|
|
a6efb8713d | ||
|
|
9b26d25aa3 | ||
|
|
bcb50cfe2c | ||
|
|
0938403561 | ||
|
|
3e2ae19f03 | ||
|
|
812da6aa3c | ||
|
|
4946aff35a | ||
|
|
0692056e95 | ||
|
|
b7188197a5 | ||
|
|
44fc361bd7 | ||
|
|
268abf778b | ||
|
|
13a3e00e6c | ||
|
|
45e05fd58b | ||
|
|
cee6d61591 | ||
|
|
3995a7b2ae | ||
|
|
70a243278a | ||
|
|
a5a25f07ac | ||
|
|
a48ad04502 | ||
|
|
73dac51758 | ||
|
|
68f18932a4 | ||
|
|
586d957650 | ||
|
|
72ddbec953 | ||
|
|
c8c22a6884 | ||
|
|
30c4d48f81 | ||
|
|
f071667776 | ||
|
|
d392e8aa7e | ||
|
|
d9e1f7f766 | ||
|
|
4badcf6a0c | ||
|
|
b7bfa6a3b2 | ||
|
|
9043e1a6b6 | ||
|
|
16c631cd6f | ||
|
|
4a1175f467 | ||
|
|
bdce2da794 | ||
|
|
fe59b77c3f | ||
|
|
e54edf94b8 | ||
|
|
d751ce6249 | ||
|
|
fa9ec1fead | ||
|
|
287acb7c76 | ||
|
|
b53d56e467 | ||
|
|
4e5bb877e3 | ||
|
|
4edc27ee7c | ||
|
|
9b1e313e2c | ||
|
|
f6c7bb5bb4 | ||
|
|
20fc7e4381 | ||
|
|
75fe658ab8 | ||
|
|
0aa2e8f52f | ||
|
|
95fdf3aa23 | ||
|
|
163a1340e5 | ||
|
|
1d6d707144 | ||
|
|
f87cc3e1c2 |
56
.github/workflows/test.yml
vendored
Normal file
56
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
emacs-version:
|
||||
- 26.3
|
||||
- 27.2
|
||||
- 28.2
|
||||
- 29.4
|
||||
experimental: [false]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
emacs-version: snapshot
|
||||
experimental: true
|
||||
- os: macos-latest
|
||||
emacs-version: snapshot
|
||||
experimental: true
|
||||
- os: windows-latest
|
||||
emacs-version: snapshot
|
||||
experimental: true
|
||||
exclude:
|
||||
- os: macos-latest
|
||||
emacs-version: 26.3
|
||||
- os: macos-latest
|
||||
emacs-version: 27.2
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: jcs090218/setup-emacs@master
|
||||
with:
|
||||
version: ${{ matrix.emacs-version }}
|
||||
|
||||
- uses: emacs-eask/setup-eask@master
|
||||
with:
|
||||
version: 'snapshot'
|
||||
|
||||
- name: Run tests
|
||||
run:
|
||||
make ci
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,7 +2,8 @@
|
||||
*.elc
|
||||
|
||||
# Packaging
|
||||
.cask
|
||||
.eask
|
||||
dist/
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -2,6 +2,29 @@
|
||||
|
||||
This document lists new features, improvements, changes, and bug fixes in each release of the package.
|
||||
|
||||
## GDScript mode 1.5.0
|
||||
|
||||
- Added the ability to toggle breakpoint on the current line instead of either adding or removing them.
|
||||
- Added keybindings matching Godot to run the project (<kbd>f5</kbd>), current scene (<kbd>f6</kbd>), continue execution (<kbd>f7</kbd>), and toggle breakpoints <kbd>F9</kbd>.
|
||||
|
||||
## GDScript mode 1.4.1
|
||||
|
||||
Thanks to @clangdo for the contribution!
|
||||
|
||||
- Fixed indent functions preventing double hanging indent in parentheses or after a `\`.
|
||||
|
||||
## GDScript mode 1.4.0
|
||||
|
||||
Big thanks to @VlachJosef and @rileyrg for their work on this release.
|
||||
|
||||
### New features
|
||||
|
||||
- Debugger support with breakpoints, code stepping, stack frames, remote scene tree, and more. See the [README](https://github.com/godotengine/emacs-gdscript-mode/blob/master/README.md) for more information.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fix scene and script selection not aborting when pressing <kbd>C-g</kbd>.
|
||||
|
||||
## GDScript mode 1.3.0
|
||||
|
||||
This release brings many quality-of-life improvements to work more productively with Godot and Emacs.
|
||||
|
||||
17
Eask
Normal file
17
Eask
Normal file
@@ -0,0 +1,17 @@
|
||||
(package "gdscript-mode"
|
||||
"0.1.0"
|
||||
"Major mode for Godot's GDScript language")
|
||||
|
||||
(website-url "https://github.com/godotengine/emacs-gdscript-mode/")
|
||||
(keywords "languages")
|
||||
|
||||
(package-file "gdscript-mode.el")
|
||||
(files "*.el")
|
||||
|
||||
(script "test" "echo \"Error: no test specified\" && exit 1")
|
||||
|
||||
(source "gnu")
|
||||
|
||||
(depends-on "emacs" "26.3")
|
||||
|
||||
(setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432
|
||||
36
Makefile
Normal file
36
Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
SHELL := /usr/bin/env bash
|
||||
|
||||
EMACS ?= emacs
|
||||
EASK ?= eask
|
||||
|
||||
.PHONY: clean checkdoc lint package install compile test
|
||||
|
||||
# TODO: add `lint` if we can?
|
||||
ci: clean package install compile checkdoc
|
||||
|
||||
package:
|
||||
@echo "Packaging..."
|
||||
$(EASK) package
|
||||
|
||||
install:
|
||||
@echo "Installing..."
|
||||
$(EASK) install
|
||||
|
||||
compile:
|
||||
@echo "Compiling..."
|
||||
$(EASK) compile
|
||||
|
||||
test:
|
||||
@echo "Testing..."
|
||||
$(EASK) ert ./test/*.el
|
||||
|
||||
checkdoc:
|
||||
@echo "Run checkdoc..."
|
||||
$(EASK) lint checkdoc
|
||||
|
||||
lint:
|
||||
@echo "Run package-lint..."
|
||||
$(EASK) lint package
|
||||
|
||||
clean:
|
||||
$(EASK) clean all
|
||||
203
README.md
203
README.md
@@ -7,34 +7,46 @@ This package adds support for the GDScript programming language from the Godot
|
||||
game engine in Emacs. It gives syntax highlighting and indentations.
|
||||
[Contributors](#contributing) are welcome!
|
||||
|
||||

|
||||
|
||||
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
|
||||
**Table of Contents**
|
||||
|
||||
- [Features](#features)
|
||||
- [Contributing](#contributing)
|
||||
- [How to install](#how-to-install)
|
||||
- [Installing in Spacemacs](#installing-in-spacemacs)
|
||||
- [Installing in Doom Emacs](#installing-in-doom-emacs)
|
||||
- [Installing with `use-package` + `straight.el`](#installing-with-use-package--straightel)
|
||||
- [Installing manually](#installing-manually)
|
||||
- [Auto-completion with the Language Server Protocol (LSP)](#auto-completion-with-the-language-server-protocol-lsp)
|
||||
- [Known issues](#known-issues)
|
||||
- [Major mode with Treesit](#major-mode-with-treesit)
|
||||
- [Install treesit](#install-treesit)
|
||||
- [Install grammar](#install-grammar)
|
||||
- [How to use](#how-to-use)
|
||||
- [Opening the project in the editor](#opening-the-project-in-the-editor)
|
||||
- [Running Godot with visual debug options](#running-godot-with-visual-debug-options)
|
||||
- [Using Hydra](#using-hydra)
|
||||
- [Formatting code with gdformat](#formatting-code-with-gdformat)
|
||||
- [Browsing the Godot API with eww](#browsing-the-godot-api-with-eww)
|
||||
- [Opening the project in the editor](#opening-the-project-in-the-editor)
|
||||
- [Running Godot with visual debug options](#running-godot-with-visual-debug-options)
|
||||
- [Using Hydra](#using-hydra)
|
||||
- [Formatting code with gdformat](#formatting-code-with-gdformat)
|
||||
- [Browsing the Godot API with eww](#browsing-the-godot-api-with-eww)
|
||||
- [Using a local copy of the Godot docs](#using-a-local-copy-of-the-godot-docs)
|
||||
- [Keyboard shortcuts](#keyboard-shortcuts)
|
||||
- [Customization](#customization)
|
||||
- [Using the debugger](#using-the-debugger)
|
||||
- [Adding and removing breakpoints](#adding-and-removing-breakpoints)
|
||||
- [Running the project with the debugger active](#running-the-project-with-the-debugger-active)
|
||||
- [Fetching an object's details](#fetching-an-objects-details)
|
||||
- [Debug Hydra](#debug-hydra)
|
||||
- [The `* Stack frame vars *` buffer](#the--stack-frame-vars--buffer)
|
||||
- [`* Inspector *` buffer](#-inspector--buffer)
|
||||
- [`* Stack dump *` buffer](#-stack-dump--buffer)
|
||||
- [`* Breakpoints *` buffer](#-breakpoints--buffer)
|
||||
- [`* Scene tree *` buffer](#-scene-tree--buffer)
|
||||
- [Adding and removing breakpoints](#adding-and-removing-breakpoints)
|
||||
- [Running the project with the debugger active](#running-the-project-with-the-debugger-active)
|
||||
- [Multi-line display](#multi-line-display)
|
||||
- [Fetching an object's details](#fetching-an-objects-details)
|
||||
- [Debug Hydra](#debug-hydra)
|
||||
- [The `* Stack frame vars *` buffer](#the--stack-frame-vars--buffer)
|
||||
- [`* Inspector *` buffer](#-inspector--buffer)
|
||||
- [`* Stack dump *` buffer](#-stack-dump--buffer)
|
||||
- [`* Breakpoints *` buffer](#-breakpoints--buffer)
|
||||
- [`* Scene tree *` buffer](#-scene-tree--buffer)
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
This mode features all the essentials:
|
||||
@@ -52,12 +64,17 @@ This mode features all the essentials:
|
||||
- Auto-completion for all the keywords in the `gdscript-keywords.el` file.
|
||||
- Run or open the project and files with Godot.
|
||||
- Browsing the API reference in Emacs.
|
||||
- Add treesit major mode support `gdscript-ts-mode` .
|
||||
|
||||

|
||||
|
||||
_Code folding in action._
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributors are welcome! Check the [issues tab](issues) for tasks to work on and open a PR anytime.
|
||||
|
||||
If you find a bug, or would like to suggest an improvement, [open a new
|
||||
If you find a bug or would like to suggest an improvement, [open a new
|
||||
issue](issues/new).
|
||||
|
||||
For code style, we follow the [Emacs lisp style
|
||||
@@ -66,29 +83,31 @@ and the [tips and
|
||||
conventions](https://www.gnu.org/software/emacs/manual/html_node/elisp/Tips.html)
|
||||
from the Emacs manual.
|
||||
|
||||
You should also check for errors and linter warnings in your code. You can do so in Emacs with flymake or flycheck but we recommend running the tool `makem.sh` provided with the repository:
|
||||
You should also check for errors and linter warnings in your code. You can do so in Emacs with flymake or flycheck, but we recommend running the tool `Eask` provided with the repository:
|
||||
|
||||
This assumes you have [Eask](https://github.com/emacs-eask/cli) installed.
|
||||
|
||||
```sh
|
||||
./makem.sh lint-compile
|
||||
eask compile
|
||||
```
|
||||
|
||||
This program will tell you if there is any problem with your code. If there's no output, everything is fine. You can run all tests like so, but note it might give you spelling errors that aren't relevant in this project:
|
||||
|
||||
```sh
|
||||
./makem.sh all
|
||||
eask lint checkdoc && eask lint package
|
||||
```
|
||||
|
||||
## How to install
|
||||
|
||||
The package is available in the [MELPA](https://melpa.org/#/) package archive. Once you [set up MELPA](https://melpa.org/#/getting-started) you can install the package from Emacs:
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
M-x package-install gdscript-mode
|
||||
```
|
||||
|
||||
Then, in your init.el file, you can require the package:
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(require 'gdscript-mode)
|
||||
```
|
||||
|
||||
@@ -96,7 +115,7 @@ Then, in your init.el file, you can require the package:
|
||||
|
||||
1. Add the package to the `dotspacemacs-additional-packages`. You can find it under the dotspacemacs/layers function:
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(defun dotspacemacs/layers ()
|
||||
"Configuration Layers declaration..."
|
||||
(setq-default
|
||||
@@ -108,60 +127,132 @@ Then, in your init.el file, you can require the package:
|
||||
|
||||
2. In your `dotspacemacs/user-config` function, require the package.
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(defun dotspacemacs/user-config ()
|
||||
(require 'gdscript-mode))
|
||||
```
|
||||
|
||||
### Installing in Doom Emacs
|
||||
|
||||
Add the following package definition to your `.doom.d/packages.el` file:
|
||||
Doom Emacs comes with a Godot GDScript module.
|
||||
|
||||
```lisp
|
||||
(package! gdscript-mode
|
||||
:recipe (:host github
|
||||
:repo "GDQuest/emacs-gdscript-mode"))
|
||||
You just need to add the "lang: gdscript" keyword to your `.doom.d/init.el` file.
|
||||
|
||||
```elisp
|
||||
:lang
|
||||
(gdscript +lsp) ; the language you waited for
|
||||
```
|
||||
|
||||
Require the package in your `.doom.d/config.el` file:
|
||||
The `+lsp` flag adds language server support for game development with Godot.
|
||||
|
||||
```lisp
|
||||
(require 'gdscript-mode)
|
||||
```
|
||||
To see the module's documentation in Emacs, place your cursor over the word `gdscript` and press <kbd>k</kbd>.
|
||||
|
||||
### Installing with `use-package` + `straight.el`
|
||||
|
||||
Add the call to use-package to your Emacs configuration:
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(use-package gdscript-mode
|
||||
:straight (gdscript-mode
|
||||
:type git
|
||||
:host github
|
||||
:repo "GDQuest/emacs-gdscript-mode"))
|
||||
:repo "godotengine/emacs-gdscript-mode"))
|
||||
```
|
||||
|
||||
### Installing manually
|
||||
|
||||
1. Clone the repository or download a [stable release](https://github.com/GDQuest/emacs-gdscript-mode/releases) to your computer.
|
||||
1. Clone the repository or download a [stable release](https://github.com/godotengine/emacs-gdscript-mode/releases) to your computer.
|
||||
1. In your init.el file, add a call to load and require the package.
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(add-to-list 'load-path "/path/to/gdscript-mode")
|
||||
(require 'gdscript-mode)
|
||||
```
|
||||
|
||||
## Auto-completion with the Language Server Protocol (LSP)
|
||||
|
||||
For auto-completion, we rely on either the [eglot](https://github.com/joaotavora/eglot) or [lsp-mode](https://emacs-lsp.github.io/lsp-mode/) packages, and the GDScript language server which is built into Godot.
|
||||
|
||||
To use the LSP with `eglot`, you need to install `eglot` on top of `gdscript-mode`, if using an Emacs version earlier than 29.
|
||||
After installation, `eglot` can be connected on startup by adding `eglot-ensure` as a hook on `gdscript-mode-hook`.
|
||||
|
||||
Note that, due to language server changes made in Godot 4, usage with Godot 3 requires `gdscript-eglot-version` to be customized to 3.
|
||||
|
||||
An example configuration for Godot 3 usage with `use-package`:
|
||||
|
||||
```elisp
|
||||
(use-package gdscript-mode
|
||||
:hook (gdscript-mode . eglot-ensure)
|
||||
:custom (gdscript-eglot-version 3))
|
||||
```
|
||||
|
||||
To use the LSP with `lsp-mode`, you need to install `lsp-mode` on top of `gdscript-mode` and configure it. To install and configure `lsp-mode`, see the [lsp-mode documentation](https://emacs-lsp.github.io/lsp-mode/page/installation/).
|
||||
|
||||
### Known issues
|
||||
|
||||
There are some known issues with the GDScript language server in Godot 3.2 due to the server being a bit young and not following the specification strictly. This mainly causes some `unknown notification` errors in lsp-mode at the moment. You can suppress them by adding the following code to your Emacs configuration (thanks to Franco Garcia for sharing this workaround):
|
||||
|
||||
```elisp
|
||||
(defun lsp--gdscript-ignore-errors (original-function &rest args)
|
||||
"Ignore the error message resulting from Godot not replying to the `JSONRPC' request."
|
||||
(if (string-equal major-mode "gdscript-mode")
|
||||
(let ((json-data (nth 0 args)))
|
||||
(if (and (string= (gethash "jsonrpc" json-data "") "2.0")
|
||||
(not (gethash "id" json-data nil))
|
||||
(not (gethash "method" json-data nil)))
|
||||
nil ; (message "Method not found")
|
||||
(apply original-function args)))
|
||||
(apply original-function args)))
|
||||
;; Runs the function `lsp--gdscript-ignore-errors` around `lsp--get-message-type` to suppress unknown notification errors.
|
||||
(advice-add #'lsp--get-message-type :around #'lsp--gdscript-ignore-errors)
|
||||
```
|
||||
|
||||
## Major mode with Treesit
|
||||
|
||||
[Treesit](https://github.com/tree-sitter/tree-sitter) is an incremental parsing system for programming tools.
|
||||
|
||||
This package has a major mode (gdscript-ts-mode). That supports the use tree-sitter for font-lock, imenu, indentation, and navigation of `gdscript` files.
|
||||
|
||||
Emacs version 29 or higher is required to use this mode.
|
||||
|
||||
### Install treesit
|
||||
|
||||
We need to install tree-sitter library, When under Arch Linux :
|
||||
|
||||
```sh
|
||||
sudo pacman -S tree-sitter
|
||||
```
|
||||
|
||||
### Install grammar
|
||||
|
||||
To support Gdscript, we must install [gdscript-grammar](https://github.com/PrestonKnopp/tree-sitter-gdscript.git):
|
||||
|
||||
```sh
|
||||
git clone https://github.com/PrestonKnopp/tree-sitter-gdscript.git
|
||||
cd tree-sitter-gdscript/src
|
||||
cc -std=c99 -c parser.c
|
||||
cc -c scanner.cc
|
||||
cc -shared parser.o scanner.o -o libtree-sitter-gdscript.so
|
||||
```
|
||||
|
||||
Additional directories to look for tree-sitter language definitions. ( DIR is your working path )
|
||||
|
||||
```emacs-lisp
|
||||
(setq treesit-extra-load-path '("DIR/tree-sitter-gdscript/src/"))
|
||||
```
|
||||
enjoy.
|
||||
|
||||
## How to use
|
||||
|
||||
### Opening the project in the editor
|
||||
|
||||
You can open the project in the Godot editor with `M-x gdscript-godot-open-project-in-editor`, or open files and more in Godot with the `M-x gdscript-godot-*` commands.
|
||||
You can open the Godot editor with `M-x gdscript-godot-open-project-in-editor`, or open files and more in Godot with the `M-x gdscript-godot-*` commands.
|
||||
|
||||
By default, these commands try to use an executable named `godot` on the system [PATH environment variable](<https://en.wikipedia.org/wiki/PATH_(variable)>).
|
||||
|
||||
If you don't have `godot` available there, you can set a custom executable name or path to use instead:
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(setq gdscript-godot-executable "/path/to/godot")
|
||||
```
|
||||
|
||||
@@ -178,24 +269,20 @@ Here are the available options:
|
||||
3. `--debug-navigation`
|
||||
4. `--debug-collisions --debug-navigation`
|
||||
|
||||
The last selected option is saved for the next time you call `gdscript-godot-run-project-debug`. To remove debug options, you need to call the command with the universal argument again.
|
||||
The last selected option is saved for the next time you call `gdscript-godot-run-project-debug`. To turn off debug options, you need to call the command with the universal argument again.
|
||||
|
||||
### Using Hydra
|
||||
|
||||
Running `gdscript-hydra-show` (<kbd>C-c r</kbd>) opens a [hydra](https://github.com/abo-abo/hydra) popup with options to open the editor or run the project, a scene, or a script, including with visual debug options.
|
||||
|
||||
```
|
||||
d ( ) Debug p run project t run script h run from history a format all q quit
|
||||
e ( ) Editor s run scene r run last g switch to *godot* b format buffer
|
||||

|
||||
|
||||
c [ ] Visible collisions shapes
|
||||
n [ ] Visible navigation
|
||||
```
|
||||
_Hydra interactive menu to run the project and set debug options on the fly._
|
||||
|
||||
### Formatting code with gdformat
|
||||
|
||||
You can call the `gdscript-format` function to format the current buffer with
|
||||
`gdformat`. Alternatively `gdscript-format-all` will reformat all gdscripts in
|
||||
`gdformat`. Alternatively, `gdscript-format-all` will reformat all GDScript files in
|
||||
the project. This feature requires the python package `gdtoolkit` to be installed
|
||||
and available on the system's PATH variable.
|
||||
|
||||
@@ -208,7 +295,7 @@ pip3 install gdtoolkit
|
||||
|
||||
### Browsing the Godot API with eww
|
||||
|
||||
With the point on a built-in class you can press `C-c C-b o` to open the code reference for that class in the text browser [eww](https://www.gnu.org/software/emacs/manual/html_node/emacs/EWW.html).
|
||||
With the point on a built-in class, you can press `C-c C-b o` to open the code reference for that class in the text browser [eww](https://www.gnu.org/software/emacs/manual/html_node/emacs/EWW.html).
|
||||
|
||||
To open the main API reference page and browse it, press `C-c C-b a`.
|
||||
|
||||
@@ -221,7 +308,7 @@ You can browse the API reference offline with `eww`. To do so:
|
||||
|
||||
For example:
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(setq gdscript-docs-local-path "/home/gdquest/Documents/docs/godot")
|
||||
```
|
||||
|
||||
@@ -255,7 +342,7 @@ To find all GDScript-mode settings, press `M-x customize` and search for "gdscri
|
||||
|
||||
Code example:
|
||||
|
||||
```lisp
|
||||
```elisp
|
||||
(setq gdscript-use-tab-indents t) ;; If true, use tabs for indents. Default: t
|
||||
(setq gdscript-indent-offset 4) ;; Controls the width of tab-based indents
|
||||
(setq gdscript-godot-executable "/path/to/godot") ;; Use this executable instead of 'godot' to open the Godot editor.
|
||||
@@ -264,13 +351,17 @@ Code example:
|
||||
|
||||
## Using the debugger
|
||||
|
||||
Emacs GDScript mode includes support for the GDScript debugger. You can use breakpoints, use code stepping functions, see your nodes' state at runtime, and more.
|
||||
Emacs GDScript mode includes support for the GDScript debugger.
|
||||
|
||||
*The debugger in this package is only for Godot 3. Godot 4 supports the Debugger Adapter Procol (DAP), which you can use with the [dap-mode](https://github.com/emacs-lsp/dap-mode) package.*
|
||||
|
||||
You can use the debugger tools to manage breakpoints, step through code, and more.
|
||||
|
||||
To get started with this feature, you need to add a least one breakpoint.
|
||||
|
||||
### Adding and removing breakpoints
|
||||
|
||||
You can add a breakpoint on the current line with `gdscript-debug-add-breakpoint` (<kbd>C-c C-d b</kbd>). A red dot should appear in the left fringe. Use `gdscript-debug-remove-breakpoint` (<kbd>C-c C-d r</kbd>) to remove a breakpoint on the current line.
|
||||
Like in Godot's editor, you can toggle a breakpoint on the current line with `gdscript-debug-toggle-breakpoint` (<kbd>F9</kbd>).
|
||||
|
||||
After adding at least one breakpoint to the project, a buffer named `* Breakpoints *` is created. This buffer displays all existing breakpoints in a project. In that buffer, pressing <kbd>D</kbd> on a breakpoint line deletes the breakpoint. Pressing <kbd>RET</kbd> opens the corresponding GDScript file in another buffer.
|
||||
|
||||
@@ -282,7 +373,7 @@ The debugger's server runs on `localhost` through port `6010` by default. You ca
|
||||
|
||||
Once Godot hits a breakpoint, Emacs displays two new buffers:
|
||||
|
||||
- `* Stack frame vars *` displays the locals, members, and globals variables for the current stack point. It show variable name, its type and its value.
|
||||
- `* Stack frame vars *` displays the locals, members, and globals variables for the current stack point. It shows the variable name, its type, and its value.
|
||||
- `* Inspector *` displays detailed information about the selected object. By default, it shows the properties of `self`.
|
||||
|
||||
You can inspect any object in those two buffers by pressing <kbd>RET</kbd> on the corresponding line.
|
||||
@@ -323,7 +414,7 @@ o pin u unpin q quit
|
||||
|
||||
### The `* Stack frame vars *` buffer
|
||||
|
||||
The stack frame buffer displays the locals, members, and globals variables for the current stack point. Here are available keyboard shortcuts:
|
||||
The stack frame buffer displays the locals, members, and global variables for the current stack point. Here are available keyboard shortcuts:
|
||||
|
||||
- <kbd>TAB</kbd> toggles multi-line display for selected types.
|
||||
- <kbd>RET</kbd> on an object line to display its details in the `* Inspector *`buffer.
|
||||
@@ -337,12 +428,12 @@ The stack frame buffer displays the locals, members, and globals variables for t
|
||||
|
||||
### `* Inspector *` buffer
|
||||
|
||||
Contains information about inspected object. By default `self` variable from `* Stack frame vars *` is displayed. Inspected object is kept to be focused until other object is inspected or until inspected object cease to exists, in which case current `self` is displayed instead.
|
||||
Contains information about inspected object. By default `self` variable from `* Stack frame vars *` is displayed. The inspected object is kept in focus until you inspect another object or until the active object ceases to exists, in which case the current `self` is displayed instead.
|
||||
|
||||
- Press <kbd>TAB</kbd> to toggle multi-line display for selected typess.
|
||||
- Press <kbd>RET</kbd> on object line to display its detailss.
|
||||
- Press <kbd>RET</kbd> on `Node/path` line (second line from the top) to show given object in `* Scene Tree *` buffers.
|
||||
- Press <kbd>l</kbd> deep in nested object to navigate one level up in the structure (ie. back). Pressing `l` while on top level object displays `* Stack frame vars *` buffers.
|
||||
- Press <kbd>l</kbd> deep in nested object to navigate one level up in the structure (ie. back). Pressing `l` while on top-level object displays `* Stack frame vars *` buffers.
|
||||
- Press <kbd>d</kbd> to display additional details for object variabless.
|
||||
- Press <kbd>p</kbd> to go to the previous lines.
|
||||
- Press <kbd>n</kbd> to go to the next lines.
|
||||
@@ -355,7 +446,7 @@ Contains information about inspected object. By default `self` variable from `*
|
||||
Contains stack dump information.
|
||||
|
||||
- Press <kbd>SPC</kbd> to jump to gdscript file where stack frame points to.
|
||||
- Press <kbd>RET</kbd> to jump to gdscript file and to show `* Stack frame vars *`, `* Inspector *` buffers and a debug hydra.
|
||||
- Press <kbd>RET</kbd> to jump to the gdscript file and show `* Stack frame vars *`, `* Inspector *` buffers, and a debug hydra.
|
||||
- Press <kbd>l</kbd> to display the `* Stack frame vars *` buffer.
|
||||
- Press <kbd>p</kbd> to go to the previous line.
|
||||
- Press <kbd>n</kbd> to go to the next line.
|
||||
|
||||
BIN
assets/emacs-gdscript-code-folding.png
Normal file
BIN
assets/emacs-gdscript-code-folding.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/emacs-gdscript-hydra.png
Normal file
BIN
assets/emacs-gdscript-hydra.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/emacs-gdscript-imenu.png
Normal file
BIN
assets/emacs-gdscript-imenu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -58,8 +58,17 @@
|
||||
ARGUMENTS are command line arguments for godot executable.
|
||||
When run it will kill existing process if one exists."
|
||||
(let ((buffer-name (gdscript-util--get-godot-buffer-name (member "-e" arguments)))
|
||||
(inhibit-read-only t))
|
||||
(if (not (or (file-executable-p gdscript-godot-executable) (executable-find gdscript-godot-executable)))
|
||||
(inhibit-read-only t)
|
||||
(godot-command gdscript-godot-executable))
|
||||
|
||||
;; support flatpak
|
||||
(when (string-match-p (rx "run" (+ space) "org.godotengine.Godot") godot-command)
|
||||
(let ((exec-split (split-string godot-command)))
|
||||
(setq godot-command (car exec-split))
|
||||
(setq arguments (append (cdr exec-split) arguments))))
|
||||
|
||||
(if (not (or (file-executable-p godot-command)
|
||||
(executable-find godot-command)))
|
||||
(error "Error: Could not execute '%s'. Please customize the `gdscript-godot-executable variable'" gdscript-godot-executable)
|
||||
(with-current-buffer (get-buffer-create buffer-name)
|
||||
(when gdscript-gdformat-save-and-format
|
||||
@@ -68,7 +77,7 @@ When run it will kill existing process if one exists."
|
||||
(godot-mode)
|
||||
(buffer-disable-undo))
|
||||
(erase-buffer)
|
||||
(comint-exec (current-buffer) buffer-name gdscript-godot-executable nil arguments)
|
||||
(comint-exec (current-buffer) buffer-name godot-command nil arguments)
|
||||
(set-process-sentinel (get-buffer-process (current-buffer)) 'gdscript-comint--sentinel)
|
||||
(pop-to-buffer (current-buffer))))))
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>, Fabián E. Gallina <fgallina@gnu.org>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.1.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -63,23 +63,24 @@ first."
|
||||
(let ((has-projectile (featurep 'projectile)))
|
||||
(when has-projectile
|
||||
(projectile-maybe-invalidate-cache arg))
|
||||
(let* ((project-root
|
||||
(if has-projectile
|
||||
(projectile-ensure-project (projectile-project-root))
|
||||
(gdscript-util--find-project-configuration-file)))
|
||||
(file
|
||||
(if has-projectile
|
||||
(projectile-completing-read
|
||||
"Find file: "
|
||||
(projectile-project-files project-root))
|
||||
(read-file-name
|
||||
"Find file: "
|
||||
project-root))))
|
||||
(when file
|
||||
(insert
|
||||
(concat "\"res://"
|
||||
(gdscript-util--get-godot-project-file-path-relative file)
|
||||
"." (file-name-extension file) "\""))))))
|
||||
(when-let* ((project-root
|
||||
(if has-projectile
|
||||
(projectile-ensure-project (projectile-project-root))
|
||||
(gdscript-util--find-project-configuration-file)))
|
||||
(file
|
||||
(if has-projectile
|
||||
(projectile-completing-read
|
||||
"Find file: "
|
||||
(projectile-project-files project-root))
|
||||
(read-file-name
|
||||
"Find file: "
|
||||
project-root)))
|
||||
(resource-path
|
||||
(if has-projectile
|
||||
file
|
||||
(concat (gdscript-util--get-godot-project-file-path-relative file)
|
||||
"." (file-name-extension file)))))
|
||||
(insert (concat "\"res://" resource-path "\"")))))
|
||||
|
||||
|
||||
(provide 'gdscript-completion)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.1.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -41,8 +41,8 @@
|
||||
|
||||
(defcustom gdscript-use-type-hints t
|
||||
"If t, inserted snippets contain type hints."
|
||||
:group 'gdscript
|
||||
:type 'boolean)
|
||||
:type 'boolean
|
||||
:group 'gdscript)
|
||||
|
||||
;; gdscript-indent
|
||||
(defcustom gdscript-use-tab-indents t "Use tabs (t) or spaces (nil)."
|
||||
@@ -54,30 +54,31 @@
|
||||
:group 'gdscript)
|
||||
|
||||
(defcustom gdscript-indent-offset 4 "Default indentation offset for Gdscript."
|
||||
:group 'gdscript
|
||||
:type 'integer
|
||||
:safe 'integerp)
|
||||
:safe 'integerp
|
||||
:group 'gdscript)
|
||||
|
||||
(defcustom gdscript-indent-trigger-commands '(indent-for-tab-command yas-expand yas/expand)
|
||||
"Commands that might trigger a `gdscript-indent-line' call."
|
||||
:type '(repeat symbol):group'gdscript)
|
||||
:type '(repeat symbol)
|
||||
:group'gdscript)
|
||||
|
||||
;; gdscript-fill-paragraph.el
|
||||
(defcustom gdscript-fill-comment-function 'gdscript-fill-paragraph-fill-comment
|
||||
(defcustom gdscript-fill-comment-function 'gdscript-fill-paragraph-fill-comment
|
||||
"Function to fill comments.
|
||||
This is the function used by `gdscript-fill-paragraph' to
|
||||
fill comments."
|
||||
:type 'symbol
|
||||
:group 'gdscript)
|
||||
|
||||
|
||||
(defcustom gdscript-fill-string-function 'gdscript-fill-paragraph-fill-string
|
||||
"Function to fill strings.
|
||||
This is the function used by `gdscript-fill-paragraph' to
|
||||
fill strings."
|
||||
:type 'symbol
|
||||
:group 'gdscript)
|
||||
|
||||
:group 'gdscript)
|
||||
(defcustom gdscript-fill-paren-function 'gdscript-fill-paragraph-fill-paren
|
||||
"Function to fill parens.
|
||||
This is the function used by `gdscript-fill-paragraph' to
|
||||
fill parens."
|
||||
@@ -88,7 +89,15 @@ fill parens."
|
||||
"Multiplier applied to indentation inside multi-line def blocks."
|
||||
:version "26.1"
|
||||
:type 'integer
|
||||
"Multiplier applied to indentation inside multi-line def blocks."
|
||||
:safe 'natnump
|
||||
:group 'gdscript)
|
||||
|
||||
(defcustom gdscript-indent-line-continuation-scale 1
|
||||
"Multiplier applied to indentation of line continuation in
|
||||
general (inside parentheses and after backslash)."
|
||||
:type 'integer
|
||||
:options '(1 2)
|
||||
:group 'gdscript)
|
||||
|
||||
(defcustom gdscript-godot-executable "godot"
|
||||
"The godot executable which is either a full path such as '~/bin/godot2.2'
|
||||
@@ -116,12 +125,17 @@ so it is not slowing down Godot execution."
|
||||
:group 'gdscript)
|
||||
|
||||
(defcustom gdscript-docs-force-online-lookup nil
|
||||
:group 'gdscript)
|
||||
"If true, calling commands like gdscript-docs-browse-api
|
||||
browses the online API reference, even if a local copy is
|
||||
available."
|
||||
:type 'boolean
|
||||
:group 'gdscript)
|
||||
|
||||
(defcustom gdscript-docs-use-eww t
|
||||
:group 'gdscript)
|
||||
"If set to false use the emacs configurable `browse-url'
|
||||
function rather than `eww' directly. `browse-url' can be
|
||||
configured to open the desktop default GUI browser, for example,
|
||||
via the variable `browse-url-browser-function'"
|
||||
:type 'boolean
|
||||
:group 'gdscript)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.0.1
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: vlach.josef@gmail.com
|
||||
@@ -1868,13 +1868,35 @@ calling `gdscript-debug--table-string'."
|
||||
(setq buffer-read-only t)
|
||||
(buffer-disable-undo))
|
||||
|
||||
(defun gdscript-debug-add-breakpoint ()
|
||||
(defun gdscript-debug-toggle-breakpoint ()
|
||||
"Add or remove a breakpoint on the line at POINT."
|
||||
(interactive)
|
||||
(let* ((breakpoint (gdscript-debug--construct-breakpoint-at-point)))
|
||||
(if (gdscript-debug--is-existing-breakpoint-p breakpoint)
|
||||
(gdscript-debug--remove-breakpoint breakpoint)
|
||||
(gdscript-debug--add-breakpoint-to-line breakpoint))))
|
||||
|
||||
(defun gdscript-debug--construct-breakpoint-at-point ()
|
||||
"Construct a breakpoint object for the line at POINT and return it.
|
||||
May match an existing breakpoint."
|
||||
(gdscript-debug--with-gdscript-file file-info
|
||||
(let* ((line (line-number-at-pos))
|
||||
(let* ((start (line-beginning-position))
|
||||
(end (line-end-position))
|
||||
(line (line-number-at-pos))
|
||||
(file (car file-info))
|
||||
(file-absolute (cdr file-info))
|
||||
(breakpoint (gdscript-breakpoint-create :file file :file-absolute file-absolute :line line)))
|
||||
breakpoint)))
|
||||
|
||||
(defun gdscript-debug--is-existing-breakpoint-p (breakpoint)
|
||||
"Return t if `BREAKPOINT' is an existing breakpoint in the project."
|
||||
(member breakpoint gdscript-debug--breakpoints))
|
||||
|
||||
(defun gdscript-debug--add-breakpoint-to-line (breakpoint)
|
||||
"Register `BREAKPOINT' to the current line in a GDScript buffer."
|
||||
(gdscript-debug--with-gdscript-file file-info
|
||||
(let* ((line (line-number-at-pos))
|
||||
(file (car file-info)))
|
||||
(if (member breakpoint gdscript-debug--breakpoints)
|
||||
(message "Breakpoint already present at %s:%s" file line)
|
||||
(gdscript-debug--add-fringe (line-beginning-position) (not gdscript-debug--skip-breakpoints) 'gdb-bptno 1)
|
||||
@@ -1884,15 +1906,13 @@ calling `gdscript-debug--table-string'."
|
||||
(gdscript-debug--send-command
|
||||
(gdscript-debug--breakpoint-command file line t)))))))
|
||||
|
||||
(defun gdscript-debug-remove-breakpoint ()
|
||||
(interactive)
|
||||
(defun gdscript-debug--remove-breakpoint (breakpoint)
|
||||
"Remove `BREAKPOINT' to the current line in a GDScript buffer."
|
||||
(gdscript-debug--with-gdscript-file file-info
|
||||
(let* ((start (line-beginning-position))
|
||||
(end (line-end-position))
|
||||
(line (line-number-at-pos))
|
||||
(file (car file-info))
|
||||
(file-absolute (cdr file-info))
|
||||
(breakpoint (gdscript-breakpoint-create :file file :file-absolute file-absolute :line line)))
|
||||
(file (car file-info)))
|
||||
(if (not (member breakpoint gdscript-debug--breakpoints))
|
||||
(message "No breakpoint at %s:%s" file line)
|
||||
(gdscript-debug--remove-strings start end)
|
||||
@@ -1920,7 +1940,9 @@ calling `gdscript-debug--table-string'."
|
||||
(prop `(left-fringe breakpoint ,(if (not enabled) 'breakpoint-enabled 'breakpoint-disabled))))
|
||||
(put-text-property 0 1 'display prop string))))))))))))
|
||||
|
||||
(defun gdscript-debug-toggle-breakpoint ()
|
||||
(defun gdscript-debug-toggle-skip-breakpoints ()
|
||||
"Toggle the execution of all breakpoints without removing them.
|
||||
Like Godot's Skip Breakpoints button."
|
||||
(interactive)
|
||||
(setq gdscript-debug--skip-breakpoints (not gdscript-debug--skip-breakpoints))
|
||||
(gdscript-debug--set-left-fringe-breakpoints gdscript-debug--skip-breakpoints)
|
||||
@@ -1937,7 +1959,7 @@ calling `gdscript-debug--table-string'."
|
||||
(with-current-buffer buffer
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- line))
|
||||
(gdscript-debug-remove-breakpoint)))))
|
||||
(gdscript-debug--remove-breakpoint breakpoint)))))
|
||||
(message "Not recognized as breakpoint line")))
|
||||
|
||||
(defun gdscript-debug-goto-breakpoint ()
|
||||
@@ -2048,7 +2070,7 @@ calling `gdscript-debug--table-string'."
|
||||
(defvar gdscript-debug--breakpoints-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(suppress-keymap map)
|
||||
(define-key map " " 'gdscript-debug-toggle-breakpoint)
|
||||
(define-key map " " 'gdscript-debug-toggle-skip-breakpoints)
|
||||
(define-key map "q" 'kill-current-buffer)
|
||||
(define-key map "D" 'gdscript-debug-delete-breakpoint)
|
||||
(define-key map "\r" 'gdscript-debug-goto-breakpoint)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -34,7 +34,7 @@
|
||||
(require 'eww)
|
||||
(require 'gdscript-customization)
|
||||
|
||||
(defun gdscript-docs-open (url &optional)
|
||||
(defun gdscript-docs-open (url &rest _)
|
||||
"when `gdscript-docs-use-eww' is true use `eww' else use `browse-url'"
|
||||
(if gdscript-docs-use-eww
|
||||
(if (file-exists-p url) (eww-open-file url) (eww-browse-url url t))
|
||||
@@ -44,7 +44,7 @@
|
||||
(defun gdscript-docs-browse-api (&optional force-online)
|
||||
"Open the main page of Godot API. Use the universal prefix (C-u) to force browsing the online API."
|
||||
(interactive)
|
||||
(if (and (or gdscript-docs-force-online-lookup current-prefix-arg force-online) (not (string= gdscript-docs-local-path "")))
|
||||
(if (and (or gdscript-docs-force-online-lookup current-prefix-arg force-online) (string= gdscript-docs-local-path ""))
|
||||
(gdscript-docs-open "https://docs.godotengine.org/en/stable/classes/index.html?#godot-api")
|
||||
(let ((file (concat (file-name-as-directory gdscript-docs-local-path) "classes/index.html")))
|
||||
(if (file-exists-p file)
|
||||
@@ -63,12 +63,12 @@ If a page is already open, switch to its buffer. Use local docs if gdscripts-doc
|
||||
(lambda (current-buffer)
|
||||
(with-current-buffer current-buffer
|
||||
(when (derived-mode-p 'eww-mode)
|
||||
(string-suffix-p symbol(string-remove-suffix ".html" (plist-get eww-data :url)) t)
|
||||
))) (buffer-list)))))
|
||||
(string-suffix-p symbol (string-remove-suffix ".html" (plist-get eww-data :url)) t))))
|
||||
(buffer-list)))))
|
||||
(if buffer (pop-to-buffer-same-window buffer)
|
||||
(if (string= "" symbol)
|
||||
(message "No symbol at point or open API reference buffers.")
|
||||
(if (and (not gdscript-docs-force-online-lookup)(not (or current-prefix-arg force-online)) (not (string= gdscript-docs-local-path "")))
|
||||
(if (and (not gdscript-docs-force-online-lookup) (not (or current-prefix-arg force-online)) (not (string= gdscript-docs-local-path "")))
|
||||
(let ((file (concat (file-name-as-directory gdscript-docs-local-path) (file-name-as-directory "classes") "class_" symbol ".html")))
|
||||
(if (file-exists-p file)
|
||||
(gdscript-docs-open file)
|
||||
|
||||
81
gdscript-eglot.el
Normal file
81
gdscript-eglot.el
Normal file
@@ -0,0 +1,81 @@
|
||||
;;; gdscript-eglot.el --- Integration with eglot -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Copyright (C) 2023 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Ruijie Yu <ruijie@netyu.xyz>
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
;; Created: June 2020
|
||||
;; Keywords: languages
|
||||
;;
|
||||
;; This file is not part of GNU Emacs.
|
||||
;;
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
;;
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Handles the configuraiton of eglot.
|
||||
;; This supports `gdscript-mode' using `eglot'.
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
;;;###autoload
|
||||
(defgroup gdscript-eglot nil
|
||||
"Configurations in gdscript related to `eglot'."
|
||||
:group 'gdscript)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom gdscript-eglot-version 4
|
||||
"The version of godot in use."
|
||||
:type 'integer)
|
||||
|
||||
;;;###autoload
|
||||
(defun gdscript-eglot-contact (_interactive)
|
||||
"Attempt to help `eglot' contact the running gdscript LSP.
|
||||
Returns a list (HOST PORT) if successful, nil otherwise. See the
|
||||
last definition of CONTACT in `eglot-server-programs' for
|
||||
definitions of HOST, PORT, and INTERACTIVE.
|
||||
|
||||
For more context, see
|
||||
https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-04/msg01070.html."
|
||||
(save-excursion
|
||||
(let* ((cfg-dir (or (getenv "XDG_CONFIG_HOME")
|
||||
(pcase system-type
|
||||
('darwin "~/Library/Application Support/Godot/")
|
||||
('windows-nt "%APPDATA%\\Godot\\")
|
||||
('gnu/linux "~/.config/"))))
|
||||
(cfg-buffer
|
||||
(find-file-noselect
|
||||
(expand-file-name
|
||||
(format "godot/editor_settings-%d.tres"
|
||||
gdscript-eglot-version)
|
||||
cfg-dir)))
|
||||
(port
|
||||
(with-current-buffer cfg-buffer
|
||||
(goto-char 0)
|
||||
(and
|
||||
(re-search-forward
|
||||
(rx "network/language_server/remote_port"
|
||||
(* space) ?= (* space)
|
||||
(group (+ digit)))
|
||||
nil t)
|
||||
(string-to-number (match-string 1))))))
|
||||
(kill-buffer cfg-buffer)
|
||||
;; then return the host-port list when found
|
||||
(and port (list "localhost" port)))))
|
||||
|
||||
(provide 'gdscript-eglot)
|
||||
;;; gdscript-eglot.el ends here.
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.1.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest, Pawel Lampe
|
||||
|
||||
;; Author: Pawel Lampe <pawel.lampe@gmail.com>, Nathan Lovato <nathan@gdquest.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Franco Eusébio Garcia <francoegarcia@outlook.com>, Nathan Lovato <nathan@gdquest.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -47,11 +47,15 @@
|
||||
(defvar gdscript-hydra--editor nil)
|
||||
(defvar gdscript-hydra--debug-collisions nil)
|
||||
(defvar gdscript-hydra--debug-navigation nil)
|
||||
(defvar gdscript-hydra--hydra nil)
|
||||
|
||||
(defun gdscript-hydra-show ()
|
||||
"Show gdcript hydra."
|
||||
(interactive)
|
||||
(gdscript-util--with-available-hydra (gdscript-hydra--menu/body)))
|
||||
(gdscript-util--with-available-hydra
|
||||
(unless gdscript-hydra--hydra
|
||||
(setq gdscript-hydra--hydra (gdscript-hydra--create)))
|
||||
(funcall gdscript-hydra--hydra)))
|
||||
|
||||
(defun gdscript-hydra--selected (selected)
|
||||
"Visual representation for (non)SELECTED checkboxes."
|
||||
@@ -110,11 +114,10 @@ on hydra checkboxes."
|
||||
"Choose command to run from history of commands."
|
||||
(gdscript-godot--run-command (gdscript-history--select-from-history)))
|
||||
|
||||
(ignore-errors
|
||||
;; Don't signal an error when hydra.el is not present
|
||||
(defun gdscript-hydra--create ()
|
||||
(defhydra gdscript-hydra--menu (:hint none
|
||||
:body-pre (setq gdscript-hydra--open t)
|
||||
:before-exit (setq gdscript-hydra--open nil))
|
||||
:body-pre (setq gdscript-hydra--open t)
|
||||
:before-exit (setq gdscript-hydra--open nil))
|
||||
"
|
||||
_d_ (?d?) Debug _p_ run project _t_ run script _h_ run from history _a_ format all _q_ quit
|
||||
_e_ (?e?) Editor _s_ run scene _r_ run last _g_ switch to *godot* _b_ format buffer
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>, Fabián E. Gallina <fgallina@gnu.org>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>, Fabián E. Gallina <fgallina@gnu.org>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -273,17 +273,19 @@ possibilities can be narrowed to specific indentation points."
|
||||
(current-column)))
|
||||
(`(,(or :after-block-start
|
||||
:after-backslash-first-line
|
||||
:after-backslash-assignment-continuation
|
||||
:inside-paren-newline-start) . ,start)
|
||||
;; Add one indentation level.
|
||||
(goto-char start)
|
||||
(+ (current-indentation) gdscript-indent-offset))
|
||||
(`(,(or :inside-paren
|
||||
:after-backslash-block-continuation
|
||||
:after-backslash-dotted-continuation) . ,start)
|
||||
;; Use the column given by the context.
|
||||
:after-backslash-dotted-continuation
|
||||
:after-backslash-assignment-continuation) . ,start)
|
||||
;; Use (possibly extra) indentation given by the configuration
|
||||
(goto-char start)
|
||||
(current-column))
|
||||
(+ (current-indentation)
|
||||
(* gdscript-indent-offset
|
||||
gdscript-indent-line-continuation-scale)))
|
||||
(`(:after-block-end . ,start)
|
||||
;; Subtract one indentation level.
|
||||
(goto-char start)
|
||||
@@ -345,11 +347,7 @@ to the maximum available level. When indentation is the minimum
|
||||
possible and PREVIOUS is non-nil, cycle back to the maximum
|
||||
level."
|
||||
(let ((follow-indentation-p
|
||||
;; Check if point is within indentation.
|
||||
(and (<= (line-beginning-position) (point))
|
||||
(>= (+ (line-beginning-position)
|
||||
(current-indentation))
|
||||
(point)))))
|
||||
(<= (current-column) (current-indentation))))
|
||||
(save-excursion
|
||||
(indent-line-to
|
||||
(gdscript-indent-calculate-indentation previous))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.1.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>, Fabián E. Gallina <fgallina@gnu.org>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.1.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -26,7 +26,7 @@
|
||||
;;; Commentary:
|
||||
|
||||
;; Adds support for the GDScript programming language from the Godot game
|
||||
;; engine. This is a domain-specific language dedicated to game programming.
|
||||
;; engine. This is a domain-specific language dedicated to game programming.
|
||||
|
||||
;;; Code:
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
(require 'gdscript-godot)
|
||||
(require 'gdscript-hydra)
|
||||
(require 'gdscript-debug)
|
||||
(require 'gdscript-eglot)
|
||||
|
||||
(when (version< "29" emacs-version)
|
||||
(require 'gdscript-ts-mode))
|
||||
|
||||
;;;###autoload
|
||||
(add-to-list 'auto-mode-alist '("\\.gd\\'" . gdscript-mode))
|
||||
@@ -49,6 +53,13 @@
|
||||
(add-to-list 'auto-mode-alist '("\\.tscn\\'" . conf-toml-mode))
|
||||
;;;###autoload
|
||||
(add-to-list 'auto-mode-alist '("\\.tres\\'" . conf-toml-mode))
|
||||
;;;###autoload
|
||||
(with-eval-after-load 'eglot
|
||||
(defvar eglot-server-programs)
|
||||
(unless (equal (alist-get 'gdscript-mode eglot-server-programs)
|
||||
#'gdscript-eglot-contact)
|
||||
(push (cons 'gdscript-mode #'gdscript-eglot-contact)
|
||||
eglot-server-programs)))
|
||||
|
||||
(defvar gdscript-mode-map (let ((map (make-sparse-keymap)))
|
||||
;; Movement
|
||||
@@ -69,8 +80,10 @@
|
||||
;; Run in Godot.
|
||||
(define-key map (kbd "C-c C-r p") 'gdscript-godot-open-project-in-editor)
|
||||
(define-key map (kbd "C-c C-r r") 'gdscript-godot-run-project)
|
||||
(define-key map (kbd "<f5>") 'gdscript-godot-run-project)
|
||||
(define-key map (kbd "C-c C-r d") 'gdscript-godot-run-project-debug)
|
||||
(define-key map (kbd "C-c C-r s") 'gdscript-godot-run-current-scene)
|
||||
(define-key map (kbd "<f6>") 'gdscript-godot-run-current-scene)
|
||||
(define-key map (kbd "C-c C-r q") 'gdscript-godot-run-current-scene-debug)
|
||||
(define-key map (kbd "C-c C-r e") 'gdscript-godot-edit-current-scene)
|
||||
(define-key map (kbd "C-c C-r x") 'gdscript-godot-run-current-script)
|
||||
@@ -85,11 +98,11 @@
|
||||
(define-key map (kbd "C-c C-d C-d d") 'gdscript-debug-display-stack-dump-buffer)
|
||||
(define-key map (kbd "C-c C-d C-d b") 'gdscript-debug-display-breakpoint-buffer)
|
||||
(define-key map (kbd "C-c C-d C-d i") 'gdscript-debug-display-inspector-buffer)
|
||||
(define-key map (kbd "C-c C-d b") 'gdscript-debug-add-breakpoint)
|
||||
(define-key map (kbd "C-c C-d r") 'gdscript-debug-remove-breakpoint)
|
||||
(define-key map (kbd "<f9>") 'gdscript-debug-toggle-breakpoint)
|
||||
(define-key map (kbd "C-c C-d q") 'gdscript-debug-make-server)
|
||||
(define-key map (kbd "C-c C-d n") 'gdscript-debug-next)
|
||||
(define-key map (kbd "C-c C-d c") 'gdscript-debug-continue)
|
||||
(define-key map (kbd "<f7>") 'gdscript-debug-continue)
|
||||
(define-key map (kbd "C-c C-d s") 'gdscript-debug-step)
|
||||
;; Debugger Hydra
|
||||
(define-key map (kbd "C-c n") 'gdscript-debug-hydra)
|
||||
@@ -119,6 +132,22 @@ the last command event was a string delimiter."
|
||||
(save-excursion
|
||||
(insert (make-string 2 last-command-event)))))
|
||||
|
||||
(defun gdscript-mark-defun ()
|
||||
"GDScript-specific version of `mark-defun'.
|
||||
|
||||
Put mark at end of this defun, point at beginning.
|
||||
The defun marked is the one that contains point or follows point.
|
||||
|
||||
If the mark is active, it marks the next defun after the one
|
||||
already marked."
|
||||
(interactive)
|
||||
(if (use-region-p)
|
||||
(gdscript-nav-forward-defun)
|
||||
(save-excursion
|
||||
(gdscript-nav-backward-defun)
|
||||
(set-mark (point))))
|
||||
(gdscript-nav-end-of-defun))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode gdscript-mode prog-mode "gdscript"
|
||||
"Major mode for editing Godot GDScript files."
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
(require 'gdscript-utils)
|
||||
|
||||
(defvar gdscript-project--script-list nil)
|
||||
|
||||
(defun gdscript-project--current-buffer-scene ()
|
||||
"Return the name of current scene.
|
||||
|
||||
@@ -64,51 +62,32 @@ If current buffer is not visiting script file return nil."
|
||||
(when (re-search-forward "^extends SceneTree\\|^extends MainLoop" nil t)
|
||||
(file-relative-name buffer-file-name (gdscript-util--find-project-configuration-file))))))
|
||||
|
||||
(defun gdscript-project--select-script ()
|
||||
(defun gdscript-project--select-script (script-list)
|
||||
"Find all script files and let user choose one."
|
||||
(let ((hydra-open gdscript-hydra--open))
|
||||
(when hydra-open (gdscript-hydra--menu/nil))
|
||||
(unwind-protect
|
||||
(let* ((prompt (format "Buffer %s is not script file, select script to run" (buffer-name)))
|
||||
(script-name (gdscript-util--read gdscript-project--script-list prompt)))
|
||||
(when script-name (gdscript-godot--run-script script-name)))
|
||||
(script-name (gdscript-util--read script-list prompt)))
|
||||
(when script-name
|
||||
(string-match "^\\(.*.gd\\):" script-name)
|
||||
(gdscript-godot--run-script (match-string 1 script-name))))
|
||||
(when hydra-open (gdscript-hydra--menu/body)))))
|
||||
|
||||
(defun gdscript-project--ag-cleanup ()
|
||||
"Clean after ag search.
|
||||
|
||||
Try to leave Emacs as it was before ag search was launched."
|
||||
(remove-hook 'ag-search-finished-hook #'gdscript-project--ag-find-next-script)
|
||||
(let* ((ag-buffer (current-buffer))
|
||||
(ag-window (get-buffer-window ag-buffer))
|
||||
(prev-buffer (window-prev-buffers ag-window)))
|
||||
(if prev-buffer (kill-buffer ag-buffer)
|
||||
(delete-window ag-window)
|
||||
(kill-buffer ag-buffer))))
|
||||
|
||||
(defun gdscript-project--ag-find-next-script ()
|
||||
"Find next script file in ag buffer."
|
||||
(let ((pos (next-single-property-change (point) 'compilation-message))
|
||||
(comp-mes (get-text-property (point) 'compilation-message)))
|
||||
(when comp-mes
|
||||
(let ((file-name (caar (compilation--loc->file-struct (compilation--message->loc comp-mes)))))
|
||||
(push file-name gdscript-project--script-list)))
|
||||
(if pos (progn (goto-char pos)
|
||||
(gdscript-project--ag-find-next-script))
|
||||
(gdscript-project--ag-cleanup)
|
||||
(with-current-buffer (window-buffer (selected-window))
|
||||
(gdscript-project--select-script)))))
|
||||
|
||||
(defun gdscript-project--get-all-scripts ()
|
||||
"Find all script files and let user choose one.
|
||||
|
||||
Since detection of script files require inspection of file contents,
|
||||
this use ag for performance."
|
||||
(if (not (featurep 'ag))
|
||||
(error (format "Buffer %s is no script file. To see all available scripts in current project install package 'ag'." (buffer-name)))
|
||||
(ag-project-regexp "^extends SceneTree|^extends MainLoop")
|
||||
(setq gdscript-project--script-list nil)
|
||||
(add-hook 'ag-search-finished-hook #'gdscript-project--ag-find-next-script)))
|
||||
(if (executable-find "ag")
|
||||
(let ((default-directory (vc-git-root default-directory)))
|
||||
(with-temp-buffer
|
||||
(call-process "ag" nil (current-buffer) nil "--vimgrep" "-s" "^extends SceneTree|^extends MainLoop")
|
||||
(let ((available-standalone-scripts (split-string (buffer-string) "\n" t)))
|
||||
(if (null available-standalone-scripts)
|
||||
(message "No standalone script found. Look at https://docs.godotengine.org/en/stable/getting_started/editor/command_line_tutorial.html#running-a-script for details.")
|
||||
(gdscript-project--select-script available-standalone-scripts)))))
|
||||
(error (format "Buffer %s is no script file. To see all available scripts install 'ag' executable." (buffer-name)))))
|
||||
|
||||
(provide 'gdscript-project)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>, Fabián E. Gallina <fgallina@gnu.org>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>, Fabián E. Gallina <fgallina@gnu.org>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest and contributors
|
||||
;;
|
||||
;; Author: Josef Vlach <vlach.josef@gmail.com>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 1.0.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
244
gdscript-ts-mode.el
Normal file
244
gdscript-ts-mode.el
Normal file
@@ -0,0 +1,244 @@
|
||||
;;; gdscript-ts-mode.el --- Summary -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2023 GDQuest and contributors
|
||||
|
||||
;; Author: xiliuya <xiliuya@aliyun.com>
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.1.0
|
||||
;; Maintainer: xiliuya <xiliuya@aliyun.com>
|
||||
;; Created: 2023-05-22 19:14:43
|
||||
|
||||
;; Keywords: languages
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Tree-sitter mode for Gdscript.(Refer to python-ts-mode)
|
||||
;; That supports the use tree-sitter for font-lock, imenu, indentation,
|
||||
;; and navigation of Gdscript files.
|
||||
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(when (version< "29" emacs-version)
|
||||
(require 'treesit))
|
||||
|
||||
|
||||
;;; Imenu
|
||||
|
||||
(defvar gdscript-ts-imenu-format-item-label-function
|
||||
'gdscript-ts-imenu-format-item-label
|
||||
"Imenu function used to format an item label.
|
||||
It must be a function with two arguments: TYPE and NAME.")
|
||||
|
||||
(defvar gdscript-ts-imenu-format-parent-item-label-function
|
||||
'gdscript-ts-imenu-format-parent-item-label
|
||||
"Imenu function used to format a parent item label.
|
||||
It must be a function with two arguments: TYPE and NAME.")
|
||||
|
||||
(defvar gdscript-ts-imenu-format-parent-item-jump-label-function
|
||||
'gdscript-ts-imenu-format-parent-item-jump-label
|
||||
"Imenu function used to format a parent jump item label.
|
||||
It must be a function with two arguments: TYPE and NAME.")
|
||||
|
||||
(defun gdscript-ts-imenu-format-item-label (type name)
|
||||
"Return Imenu label for single node using TYPE and NAME."
|
||||
(format "%s (%s)" name type))
|
||||
|
||||
(defun gdscript-ts-imenu-format-parent-item-label (type name)
|
||||
"Return Imenu label for parent node using TYPE and NAME."
|
||||
(format "%s..." (gdscript-ts-imenu-format-item-label type name)))
|
||||
|
||||
(defun gdscript-ts-imenu-format-parent-item-jump-label (type _name)
|
||||
"Return Imenu label for parent node jump using TYPE and NAME."
|
||||
(if (string= type "class")
|
||||
"*class definition*"
|
||||
"*function definition*"))
|
||||
|
||||
;;; Keywords
|
||||
|
||||
(defvar gdscript-ts--treesit-keywords '("and" "as" "break" "class" "class_name"
|
||||
"const" "continue" "elif" "else" "enum" "export" "extends" "for" "func" "if" "in" "is"
|
||||
"master" "match" "not" "onready" "or" "pass" "puppet" "remote" "remotesync" "return" "setget" "signal"
|
||||
"var" "while"))
|
||||
|
||||
|
||||
;;; Setting
|
||||
|
||||
(defvar gdscript-ts--treesit-settings
|
||||
(treesit-font-lock-rules
|
||||
:language 'gdscript
|
||||
:feature 'comment
|
||||
'((comment) @font-lock-comment-face)
|
||||
|
||||
:language 'gdscript
|
||||
:feature 'definition
|
||||
'((function_definition (name) @font-lock-function-name-face)
|
||||
(class_definition
|
||||
(name) @font-lock-function-name-face)
|
||||
(parameters (identifier) @font-lock-variable-name-face))
|
||||
|
||||
:language 'gdscript
|
||||
:feature 'keyword
|
||||
`(([,@gdscript-ts--treesit-keywords] @font-lock-keyword-face)
|
||||
([(false) (true)] @font-lock-keyword-face))
|
||||
|
||||
:language 'gdscript
|
||||
:feature 'string
|
||||
'((string) @font-lock-string-face)
|
||||
|
||||
:language 'gdscript
|
||||
:feature 'type
|
||||
'(((type) @font-lock-type-face)
|
||||
(get_node) @font-lock-type-face)
|
||||
|
||||
:feature 'function
|
||||
:language 'gdscript
|
||||
'((call (identifier) @font-lock-function-call-face)
|
||||
(attribute_call (identifier) @font-lock-function-call-face))
|
||||
|
||||
:language 'gdscript
|
||||
:feature 'variable
|
||||
'((_ (name) @font-lock-variable-name-face))
|
||||
|
||||
:feature 'number
|
||||
:language 'gdscript
|
||||
'(([(integer) (float)] @font-lock-number-face))
|
||||
|
||||
:feature 'property
|
||||
:language 'gdscript
|
||||
'((attribute (identifier) (identifier) @font-lock-property-use-face))
|
||||
|
||||
:feature 'operator
|
||||
:language 'gdscript
|
||||
`(["+" "-" "*" "/" "^" ">" "<" "="] @font-lock-operator-face)))
|
||||
|
||||
|
||||
;;; Funtion
|
||||
|
||||
(defun gdscript-ts--treesit-defun-name (node)
|
||||
"Return the defun name of NODE."
|
||||
(treesit-node-text (treesit-search-subtree node "^name$" nil t) t))
|
||||
|
||||
(defun gdscript-ts--imenu-treesit-create-index-1 (node)
|
||||
"Given a sparse tree, create an imenu alist.
|
||||
|
||||
NODE is the root node of the tree returned by
|
||||
`treesit-induce-sparse-tree' (not a tree-sitter node, its car is
|
||||
a tree-sitter node). Walk that tree and return an imenu alist.
|
||||
|
||||
Return a list of ENTRY where
|
||||
|
||||
ENTRY := (NAME . MARKER)
|
||||
| (NAME . ((JUMP-LABEL . MARKER)
|
||||
ENTRY
|
||||
...)
|
||||
|
||||
NAME is the function/class's name, JUMP-LABEL is like \"*function
|
||||
definition*\"."
|
||||
(let* ((ts-node (car node))
|
||||
(children (cdr node))
|
||||
(subtrees (mapcan #'gdscript-ts--imenu-treesit-create-index-1
|
||||
children))
|
||||
(type (pcase (treesit-node-type ts-node)
|
||||
("function_definition" 'def)
|
||||
("export_variable_statement" 'e-var)
|
||||
("onready_variable_statement" 'o-var)
|
||||
("variable_statement" 'var)
|
||||
("class_definition" 'class)))
|
||||
;; The root of the tree could have a nil ts-node.
|
||||
(name (when ts-node
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Anonymous")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
(cond
|
||||
((null ts-node)
|
||||
subtrees)
|
||||
(subtrees
|
||||
(let ((parent-label
|
||||
(funcall gdscript-ts-imenu-format-parent-item-label-function
|
||||
type name))
|
||||
(jump-label
|
||||
(funcall
|
||||
gdscript-ts-imenu-format-parent-item-jump-label-function
|
||||
type name)))
|
||||
`((,parent-label
|
||||
,(cons jump-label marker)
|
||||
,@subtrees))))
|
||||
(t (let ((label
|
||||
(funcall gdscript-ts-imenu-format-item-label-function
|
||||
type name)))
|
||||
(list (cons label marker)))))))
|
||||
|
||||
(defun gdscript-ts-imenu-treesit-create-index (&optional node)
|
||||
"Return tree Imenu alist for the current Gdscript buffer.
|
||||
|
||||
Change `gdscript-ts-imenu-format-item-label-function',
|
||||
`gdscript-ts-imenu-format-parent-item-label-function',
|
||||
`gdscript-ts-imenu-format-parent-item-jump-label-function' to
|
||||
customize how labels are formatted.
|
||||
|
||||
NODE is the root node of the subtree you want to build an index
|
||||
of. If nil, use the root node of the whole parse tree.
|
||||
|
||||
Similar to `gdscript-imenu-create-index' but use tree-sitter."
|
||||
(let* ((node (or node (treesit-buffer-root-node 'gdscript)))
|
||||
(tree (treesit-induce-sparse-tree
|
||||
node
|
||||
(rx (or (seq bol
|
||||
(or "onready_" "export_" "")
|
||||
"variable_statement"
|
||||
eol)
|
||||
(seq bol
|
||||
(or "function" "class")
|
||||
"_definition"
|
||||
eol)))
|
||||
nil 1000)))
|
||||
(gdscript-ts--imenu-treesit-create-index-1 tree)))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode gdscript-ts-mode gdscript-mode "Gdscript"
|
||||
"Major mode for editing gdscript files, using tree-sitter library.
|
||||
|
||||
\\{gdscript-ts-mode-map}"
|
||||
:syntax-table gdscript-mode-syntax-table
|
||||
(when (treesit-ready-p 'gdscript)
|
||||
(treesit-parser-create 'gdscript)
|
||||
(setq-local treesit-font-lock-feature-list
|
||||
'(( comment definition)
|
||||
( keyword string type)
|
||||
( function variable number property operator)))
|
||||
(setq-local treesit-font-lock-settings gdscript-ts--treesit-settings)
|
||||
;;; TODO: create-imenu
|
||||
(setq-local imenu-create-index-function
|
||||
#'gdscript-ts-imenu-treesit-create-index)
|
||||
(setq-local treesit-defun-type-regexp (rx (seq bol
|
||||
(or "function" "class")
|
||||
"_definition"
|
||||
eol)))
|
||||
(setq-local treesit-defun-name-function
|
||||
#'gdscript-ts--treesit-defun-name)
|
||||
(treesit-major-mode-setup)
|
||||
|
||||
|
||||
(add-to-list 'auto-mode-alist '("\\.gd\\'" . gdscript-ts-mode))
|
||||
(add-to-list 'interpreter-mode-alist '("gdscript[0-9.]*" . gdscript-ts-mode))))
|
||||
|
||||
(provide 'gdscript-ts-mode)
|
||||
;;; gdscript-ts-mode.el ends here
|
||||
@@ -3,7 +3,7 @@
|
||||
;; Copyright (C) 2020 GDQuest
|
||||
|
||||
;; Author: Nathan Lovato <nathan@gdquest.com>, Fabián E. Gallina <fgallina@gnu.org>
|
||||
;; URL: https://github.com/GDQuest/emacs-gdscript-mode/
|
||||
;; URL: https://github.com/godotengine/emacs-gdscript-mode/
|
||||
;; Version: 0.1.0
|
||||
;; Package-Requires: ((emacs "26.3"))
|
||||
;; Maintainer: nathan@gdquest.com
|
||||
|
||||
Reference in New Issue
Block a user