20 Commits
1.3.0 ... 1.4.0

Author SHA1 Message Date
Nathan Lovato
ef7a7f2789 Update the debugger's documentation, add a table of contents 2020-10-11 20:08:25 -06:00
Nathan Lovato
55a6637424 Merge pull request #94 from VlachJosef/master
Debugger support
2020-10-11 18:22:24 -06:00
Josef Vlach
58ef86f8d3 Pin/Unpin ObjectId, error message stackcall processed correctly 2020-10-11 16:39:03 +01:00
Josef Vlach
7375291bca Mark unused variables 2020-10-08 22:09:37 +01:00
Josef Vlach
a26c1d3bda README update 2020-10-08 21:59:48 +01:00
Josef Vlach
c5d34c22d5 Display buffer handling, fetching details rework 2020-10-08 21:00:21 +01:00
Josef Vlach
a9263e30ae Signed 64-bit integer support 2020-10-03 20:15:00 +01:00
Josef Vlach
d9b7c26c89 Signed 32-bit integer support, Emacs gets focus on enter debug command 2020-09-26 23:06:24 +01:00
Josef Vlach
c5da04810d Multiline property support for Stack frame vars / Inspector buffers 2020-09-26 13:13:03 +01:00
Josef Vlach
341495023a Scene Tree <-> Inspector integration. Stack Frame Vars improvements 2020-09-22 21:39:29 +01:00
Josef Vlach
5c17d7b4b9 Improved Inspector integration with Scene Tree and use of macros from subr-x 2020-09-21 21:51:16 +01:00
Josef Vlach
e457b05d2a Scene tree - basic rendering and Inspector integration 2020-09-20 22:00:25 +01:00
Josef Vlach
406bc58d77 Breadcrumbs in Inspector buffer (navigation deeper into the tree) 2020-09-19 22:40:54 +01:00
Josef Vlach
6621b71a1a *Stack frame vars* and *Inspector* buffers are table based + types for ObjectId 2020-09-19 16:03:59 +01:00
Josef Vlach
152e1b8cea Debug Hydra 2020-09-15 21:40:20 +01:00
Josef Vlach
ea94ba5360 Support all packet types and theirs (initial) to-string implementation 2020-09-15 20:40:31 +01:00
Josef Vlach
34a88c5cb2 * Stack frame vars * buffer now displays types of ObjectID variables 2020-09-12 22:47:10 +01:00
Josef Vlach
80b08e0afd Debugger - initial support 2020-09-12 11:25:36 +01:00
RichieHH
dde7ffa735 Fix scene and script selection not aborting when pressing C-g (#90)
* abort run if user cancels (C-g) a scene/script selection.

* removed todo
2020-09-09 09:14:27 -06:00
Nathan Lovato
1031e6f87e Update banner image in README 2020-09-07 22:36:40 -06:00
10 changed files with 2650 additions and 30 deletions

154
README.md
View File

@@ -1,18 +1,47 @@
# GDScript mode for Emacs
![banner showing the "GDScript mode" title with GDScript code in the
background](assets/banner.svg)
background](assets/banner.png)
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)
- [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)
- [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)
<!-- markdown-toc end -->
## Features
This mode already features all the essentials:
This mode features all the essentials:
- Syntax highlighting.
- Code folding.
- Debugger support.
- [Imenu](https://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html).
- Support for scenes (`.tscn`) and script (`.gd`) files.
- Comment wrapping when using `fill-paragraph`.
@@ -217,7 +246,8 @@ The following shortcuts are available by default:
- <kbd>C-c C-b a</kbd> `gdscript-docs-browse-api`
- <kbd>C-c C-b o</kbd> `gdscript-docs-browse-symbol-at-point`
- Open hydra:
- <kbd>C-c r</kbd> `gdscript-hydra-show` (require hydra package to be installed
- <kbd>C-c r</kbd> `gdscript-hydra-show` (require hydra package to be installed)
- <kbd>C-c n</kbd> `gdscript-debug-hydra` (require hydra package to be installed)
## Customization
@@ -231,3 +261,121 @@ Code example:
(setq gdscript-godot-executable "/path/to/godot") ;; Use this executable instead of 'godot' to open the Godot editor.
(setq gdscript-gdformat-save-and-format t) ;; Save all buffers and format them with gdformat anytime Godot executable is run.
```
## 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.
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.
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.
### Running the project with the debugger active
When any breakpoint exists, running the project with `gdscript-godot-run-project` will automatically start the debugger's server if one isn't already running and connect to it.
The debugger's server runs on `localhost` through port `6010` by default. You can customize the port with the `gdscript-debug-port` variable.
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.
- `* 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.
#### Multi-line display
You can toggle between one-line and multi-line display for values of type `Dictionary`, `PoolRealArray`, `PoolStringArray`, `PoolVector2Array`, `PoolVector3Array` and `PoolColorArray`. To do so, press `TAB` on the corresponding line.
### Fetching an object's details
Pressing <kbd>d</kbd> in `* Stack frame vars *` or `* Inspector *` buffers (or in the debug hydra) will fetch on the background data for all objects present in those two buffers and redisplay once done. Doing that adds two extra bits of information about the objects:
- Their real type, for example, `KinematicBody2D` instead of `ObjectId`.
- Their node path.
### Debug Hydra
If `hydra` is available, the debug hydra displays below `* Stack frame vars *` and `* Inspector *` buffers upon hitting a breakpoint.
You can also call it by pressing <kbd>C-c n</kbd>.
```
n next c continue m step b breakpoints s stack v vars i inspector t scene-tree d details
o pin u unpin q quit
```
- <kbd>n</kbd> - Steps to the next line of code.
- <kbd>c</kbd> - Continue program execution until the next breakpoint.
- <kbd>m</kbd> - Steps into the code.
- <kbd>s</kbd> - Shows the `* Stack dump *` buffer.
- <kbd>v</kbd> - Shows the `* Stack frame vars *` buffer.
- <kbd>i</kbd> - Shows the `* Inspector *` buffer.
- <kbd>t</kbd> - Shows the `* Scene tree *` buffer.
- <kbd>d</kbd> - Fetches details for all object present in the `* Stack frame vars *` and `* Inspector *` buffers and redisplay the buffers.
- <kbd>o</kbd> - Pins `self` in the `* Inspector *` buffer. It stays displayed until Godot frees the instance or you unpin it.
- <kbd>u</kbd> - Unpins the currently pinned object.
- <kbd>q</kbd> - Closes the debug hydra.
### 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:
- <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.
- <kbd>l</kbd> displays the `* Stack dump *` buffer.
- <kbd>d</kbd> displays additional details for `ObjectId` variables.
- <kbd>p</kbd> goes to the previous line.
- <kbd>n</kbd> goes to the next line.
- <kbd>o</kbd> pins the current object in the `* Inspector *` buffer.
- <kbd>u</kbd> unpins the currently pinned object.
- <kbd>q</kbd> closes the buffer.
### `* 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.
- 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>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.
- Press <kbd>o</kbd> to pin current object in `* Inspector *` buffers.
- Press <kbd>u</kbd> to unpin currently pinned objects.
- Press <kbd>q</kbd> to close the buffers.
### `* Stack dump *` buffer
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>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.
- Press <kbd>q</kbd> to close the buffer.
### `* Breakpoints *` buffer
Lists all existing breakpoints in the project.
- Press <kbd>SPC</kbd> to enable or disable all breakpoints.
- Press <kbd>RET</kbd> to jump to the file and line corresponding to the breakpoint..
- Press <kbd>TAB</kbd> to display the `* Stack dump *` buffer.
- Press <kbd>D</kbd> to delete the breakpoint.
- Press <kbd>q</kbd> to close the buffer.
### `* Scene tree *` buffer
Contains a tree visualisation of all objects in the running program.
- Press <kbd>RET</kbd> to open the corresponding object in the `* Inspector *` buffer.
- Press <kbd>p</kbd> to go to the previous line.
- Press <kbd>n</kbd> to go to the next line.
- Press <kbd>q</kbd> to close the buffer.

BIN
assets/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -37,6 +37,7 @@
(require 'comint)
(require 'compile)
(require 'gdscript-customization)
(require 'gdscript-debug)
(require 'gdscript-format)
(require 'gdscript-utils)
@@ -47,6 +48,7 @@
comint-mode-map))
(define-key map (kbd "C-a") 'comint-bol)
(define-key map (kbd "C-c r") 'gdscript-hydra-show)
(define-key map (kbd "C-c n") 'gdscript-debug-hydra)
map)
"Basic mode map for `godot-mode'.")
@@ -76,9 +78,13 @@ When run it will kill existing process if one exists."
Set process's buffer `inhibit-read-only' temporalily to value t,
so that `internal-default-process-sentinel' can insert status
message into the processs buffer."
(with-current-buffer (process-buffer process)
(let ((inhibit-read-only t))
(internal-default-process-sentinel process event))))
(cond
((string-match "hangup: 1\n" event)
nil)
(t
(with-current-buffer (process-buffer process)
(let ((inhibit-read-only t))
(internal-default-process-sentinel process event))))))
(define-derived-mode godot-mode comint-mode "godot"
"Major mode for godot.

View File

@@ -139,6 +139,11 @@ directory path containing the file `index.html'."
(defcustom gdscript-docs-online-search-api-url "https://docs.godotengine.org/en/stable/search.html?q=%s&check_keywords=yes&area=default"
"Online Godot API search url"
:type 'string
:group 'gdscript)
(defcustom gdscript-debug-port 6010
"Debugger server port."
:type 'integer
:group 'gdscript)

2422
gdscript-debug.el Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -34,6 +34,7 @@
(require 'gdscript-comint)
(require 'gdscript-customization)
(require 'gdscript-debug)
(require 'gdscript-history)
(require 'gdscript-project)
(require 'gdscript-utils)
@@ -70,6 +71,17 @@ The output of the process will be provided in a buffer named
`*godot - <project-name>*'."
(let ((args (gdscript-util--flatten arguments)))
(gdscript-history--add-to-history args)
(when (and gdscript-debug--breakpoints (not (member "-e" arguments)))
;; Start debugger server if it is not running already
(unless (get-process (gdscript-debug-process-name (gdscript-util--find-project-configuration-file)))
(gdscript-debug-make-server))
(push (mapconcat (lambda (breakpoint)
(let ((file (gdscript-breakpoint->file breakpoint))
(line (gdscript-breakpoint->line breakpoint)))
(format "%s:%s" file line))) gdscript-debug--breakpoints ",") args)
(push "--breakpoints" args)
(push (format "127.0.0.1:%s" gdscript-debug-port) args)
(push "--remote-debug" args))
(gdscript-comint--run (append (gdscript-godot--build-shell-command) args))
(setq gdscript-godot--debug-options-hydra :not-list)))
@@ -102,20 +114,26 @@ When run with prefix argument, it offers extra debug options to choose from."
(defun gdscript-godot-run-current-scene ()
"Run the current script file in Godot Engine. Use the universal prefix (C-u) to force a scene select."
(interactive)
(gdscript-godot--run-command (gdscript-godot--select-scene current-prefix-arg)))
(let ((scene (gdscript-godot--select-scene current-prefix-arg)))
(when scene
(gdscript-godot--run-command scene))))
(defun gdscript-godot-run-current-scene-debug ()
"Run the current script file in Godot Engine.
When run with prefix argument, it offers extra debug options to choose from."
(interactive)
(gdscript-godot--debug-options-handler debug-options
(gdscript-godot--run-command "-d" debug-options (gdscript-godot--select-scene))))
(let ((scene (gdscript-godot--select-scene current-prefix-arg)))
(when scene
(gdscript-godot--debug-options-handler debug-options
(gdscript-godot--run-command "-d" debug-options scene)))))
(defun gdscript-godot-edit-current-scene ()
"Run the current script file in Godot Engine."
(interactive)
(gdscript-godot--run-command "-e" (gdscript-godot--select-scene current-prefix-arg)))
(let ((scene (gdscript-godot--select-scene current-prefix-arg)))
(when scene
(gdscript-godot--run-command "-e" scene))))
(defun gdscript-godot--select-scene (&optional select-scene)
"Select scene to run"

View File

@@ -51,9 +51,7 @@
(defun gdscript-hydra-show ()
"Show gdcript hydra."
(interactive)
(when (not (featurep 'hydra))
(error "No `hydra.el' available. To execute `gdscript-hydra-show' command you need to install hydra.el"))
(gdscript-hydra--menu/body))
(gdscript-util--with-available-hydra (gdscript-hydra--menu/body)))
(defun gdscript-hydra--selected (selected)
"Visual representation for (non)SELECTED checkboxes."

View File

@@ -41,6 +41,7 @@
(require 'gdscript-rx)
(require 'gdscript-godot)
(require 'gdscript-hydra)
(require 'gdscript-debug)
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.gd\\'" . gdscript-mode))
@@ -79,6 +80,19 @@
(define-key map (kbd "C-c C-b s") 'gdscript-docs-online-search-api)
;; Hydra
(define-key map (kbd "C-c r") 'gdscript-hydra-show)
;; Debugger
(define-key map (kbd "C-c C-d C-d s") 'gdscript-debug-display-stack-frame-vars-buffer)
(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 "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 "C-c C-d s") 'gdscript-debug-step)
;; Debugger Hydra
(define-key map (kbd "C-c n") 'gdscript-debug-hydra)
map)
"Keymap for `gdscript-mode'.")

View File

@@ -46,12 +46,13 @@ If current buffer is not visiting scene file return nil."
(when (file-exists-p scene-name) scene-name))))
(defun gdscript-project--select-scene ()
"Find all scenes files and let user choose one."
"Find all scenes files and let user choose one. Return `nil' if user cancels selection."
(message "selecting scene")
(let* ((rl (gdscript-util--find-project-configuration-file))
(scene-list (mapcar (lambda (x) (file-relative-name x rl)) (directory-files-recursively rl ".*.tscn" t)))
(prompt (format "Select scene to run" (buffer-name))))
(gdscript-util--read scene-list prompt)))
(prompt (format "Select scene to run" (buffer-name)))
(selected-scene (gdscript-util--read scene-list prompt)))
selected-scene))
(defun gdscript-project--current-buffer-script ()
"Return the name of current script.
@@ -70,7 +71,7 @@ If current buffer is not visiting script file return 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)))
(gdscript-godot--run-script script-name))
(when script-name (gdscript-godot--run-script script-name)))
(when hydra-open (gdscript-hydra--menu/body)))))
(defun gdscript-project--ag-cleanup ()

View File

@@ -99,11 +99,12 @@ Start the search from START-PATH if provided. Otherwise, the search
starts from the current buffer path.
WARNING: the Godot project must exist for this function to work."
(let ((base-path (or start-path default-directory)))
(expand-file-name
(locate-dominating-file base-path
(lambda (parent)
(directory-files parent t "project.godot"))))))
(let* ((base-path (or start-path default-directory))
(dominating-file
(locate-dominating-file base-path
(lambda (parent)
(directory-files parent t "project.godot")))))
(when dominating-file (expand-file-name dominating-file))))
(defun gdscript-util--get-godot-project-name ()
"Retrieve the project name from Godot's configuration file."
@@ -124,9 +125,10 @@ WARNING: the Godot project must exist for this function to work."
(defun gdscript-util--get-godot-project-file-path-relative (file-path)
"Return the relative path of `FILE-PATH' to Godot's configuration file."
(concat (file-name-sans-extension
(file-relative-name file-path
(gdscript-util--find-project-configuration-file)))))
(let ((project-configuration-file (gdscript-util--find-project-configuration-file)))
(when project-configuration-file
(concat (file-name-sans-extension
(file-relative-name file-path project-configuration-file))))))
(defun gdscript-util--flatten (xs)
"Flatten deeply nested list.
@@ -142,11 +144,9 @@ For example:
(defun gdscript-util--read (items &optional prompt)
"Let's choose single item from ITEMS from mini-buffer.
PROMPT is prompt for read command."
(message "gdscript util read")
(let ((p (if prompt prompt "Options")))
(cond ((and (featurep 'projectile) )
PROMPT is prompt for read command. Return `nil' if user aborts."
(let* ((p (if prompt prompt "Options"))
(result (cond ((and (featurep 'projectile) )
(projectile-completing-read (format "%s: " p) items))
((fboundp 'ivy-read)
(ivy-read (format "%s: " p) items))
@@ -154,6 +154,14 @@ PROMPT is prompt for read command."
(ido-completing-read (format "%s: " p) items))
(t
(completing-read (format "%s (hit TAB to auto-complete): " p) items nil t)))))
(if quit-flag nil result)))
(defmacro gdscript-util--with-available-hydra (&rest body)
""
`(progn
(when (not (featurep 'hydra))
(error "No `hydra.el' available. To execute `gdscript-hydra-show' command you need to install hydra.el"))
,@body))
(provide 'gdscript-utils)