Skip to content

Commit

Permalink
Merge pull request #1 from bamboo/bamboo/repl_server
Browse files Browse the repository at this point in the history
Add repl support (including live coding with Emacs via geiser)
  • Loading branch information
bamboo authored Nov 30, 2024
2 parents bb068fc + bb683ed commit d514344
Show file tree
Hide file tree
Showing 31 changed files with 1,416 additions and 194 deletions.
7 changes: 0 additions & 7 deletions .ccls

This file was deleted.

5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ custom.py

# Ignore generated compile_commands.json
compile_commands.json
.ccls
.ccls-cache/

# Ignore files generated for documentation
/src/gen

# Ignore files generated for the repl
/src/repl/gen

# Binaries
*.o
*.os
Expand Down
15 changes: 7 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@ bin/s7: s7/s7.c
@echo ⚙️ Building scheme interpreter
gcc s7/s7.c -o bin/s7 -DWITH_MAIN -DWITH_SYSTEM_EXTRAS -DWITH_C_LOADER=0 -I. -O2 -g -ldl -lm

demo/.godot: $(wildcard demo/addons/**) $(wildcard demo/bin/**) build
@echo 📦 Importing test scene
godot --path demo --headless --import

.PHONY: build
SRC_FILES := $(shell find src -type f ! -name "*.os")
DEMO_FILES := $(shell find demo -type f -name "*.tscn" -or -name "*.scm")

build:
demo/.godot: $(SRC_FILES) $(DEMO_FILES)
@echo ⚙️ Building extension
@scons
@echo 📦 Importing test scene
godot --path demo --headless --import

.PHONY: run

run:
scons && godot -e --path demo main.tscn
run: demo/.godot
godot -e --path demo main.tscn

.PHONY: android

Expand Down
59 changes: 33 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ A more complete example of the available syntax:
(define button (*node* 'owner '(get_child 1)))
(define (button-append! suffix)
(let ((text (button 'text)))
;; Godot properties are set via generalized set! syntax
;; and there are two main ways of calling Godot methods:
;; * (! <obj> <method symbol> &<args>)
;; * (<obj> '(<method symbol> &<args>))
;; ! is preferred for effectful calls such as
;; 'insert below, and, in general is more amenable
;; to optimisations. Applicable object syntax
;; is convenient for const methods like '(length) below and
;; `(get_child 1) above.
(set! (button 'text)
(! text 'insert (text '(length)) suffix))))
(let ((text (button 'text)))
;; Godot properties are set via generalized set! syntax
;; and there are two main ways of calling Godot methods:
;; * (! <obj> <method symbol> &<args>)
;; * (<obj> '(<method symbol> &<args>))
;; ! is preferred for effectful calls such as
;; 'insert below, and, in general is more amenable
;; to optimisations. Applicable object syntax
;; is convenient for const methods like '(length) below and
;; `(get_child 1) above.
(set! (button 'text)
(! text 'insert (text '(length)) suffix))))
(define (function-handler)
(button-append! "!"))
(button-append! "!"))
(define (symbol-handler)
(button-append! "'"))
(button-append! "'"))
;; Signals can be connected to symbols, lambdas and arbitrary procedures.
;; Symbols provide late binding, i.e., the ability to redefine the
Expand All @@ -57,19 +57,19 @@ Very experimental but a lot of fun to play with. Use it at your own risk.
Make sure to update all git submodules:

```shell
git submodule update --init
git submodule update --init
```

Build and launch the demo project with:
Build and launch the demo project with `make run` or more explicitly via:

```shell
scons && godot -e --path demo
scons && godot -e --path demo
```

Build the Android target with:
Build the Android target with `make android` or more explicitly via:

```shell
scons platform=android target=template_debug
scons platform=android target=template_debug
```

Make sure `ANDROID_HOME` is set.
Expand All @@ -79,22 +79,29 @@ Make sure `ANDROID_HOME` is set.
Install [Geiser](https://www.nongnu.org/geiser/) then add the following to your Emacs configuration:

```elisp
(add-to-list 'load-path "~/path/to/godot-s7-scheme/emacs/")
(load "geiser-godot-s7-autoloads.el")
(add-to-list 'load-path "~/path/to/godot-s7-scheme/emacs/")
(load "geiser-godot-s7-autoloads.el")
```

The Emacs extension automatically recognize Scheme files inside Godot project directories as `Godot s7 Scheme` files.

### Connecting
### Connecting to the editor

1. Add a `SchemeReplServer` to your scene (preferably as a child of a `Scheme` node) and set its `Auto Start` property to `true`.
2. Check the port number in the Godot output window.
3. `M-x connect-to-godot-s7`
1. Start Godot with `--s7-tcp-port=<port-number>` (and/or `--s7-tcp-address=<bind-address>`).
2. Check the port number in the console.
3. In Emacs, `M-x connect-to-godot-s7`
3.1 You can also open a Scheme repl from the shell with `nc <bind-address> <port-number>`

### Connecting to a running scene

1. In Godot, select `Debug / Customize Run Instances... / Main Run Args`
- Add `--s7-tcp-port=<port-number>` and/or `--s7-tcp-address=<bind-address>`.
2. Steps 2 and 3 as above.

## Roadmap

- [x] use Godot API from Scheme
- [o] live coding interface via Emacs (wip)
- [x] live coding interface via Emacs
- [ ] expose tree-sitter API to Scheme
- [ ] Scheme editor with syntax highlighting
- [ ] Scheme notebooks
Expand Down
78 changes: 54 additions & 24 deletions SConstruct
Original file line number Diff line number Diff line change
@@ -1,39 +1,62 @@
#!/usr/bin/env python
import os
import sys

from methods import print_error

# -------------------------- Utility Functions --------------------------
def embed_file(target, source, env):
"""
Embeds the content of <source> file into a <target> header file as a const char* constant.
"""
target_path = str(target[0])
source_path = str(source[0])

# Read the content of the source file
with open(source_path, 'r') as src_file:
file_content = src_file.read()

# Generate a unique header guard based on the file name
target_file_name = os.path.basename(target_path)
header_guard = target_file_name.replace('-', '_').replace('.', '_').upper()

# Write the output header file
constant_name = os.path.splitext(target_file_name)[0].replace('-', '_')
with open(target_path, 'w') as target_file:
target_file.write(f"""
#ifndef {header_guard}
#define {header_guard}
const char* {constant_name} = R"({file_content})";
#endif // {header_guard}
""")

libname = "godot-s7-scheme"
projectdir = "demo"
def is_submodule_initialized(path):
return os.path.isdir(path) and os.listdir(path)

localEnv = Environment(tools=["default"], PLATFORM="")
# -------------------------- Build definition --------------------------

lib_name = "godot-s7-scheme"
project_dir = "demo"

local_env = Environment(tools=["default"], PLATFORM="")

customs = ["custom.py"]
customs = [os.path.abspath(path) for path in customs]

opts = Variables(customs, ARGUMENTS)
opts.Update(localEnv)

Help(opts.GenerateHelpText(localEnv))
opts.Update(local_env)

env = localEnv.Clone()
Help(opts.GenerateHelpText(local_env))

submodule_initialized = False
dir_name = 'godot-cpp'
if os.path.isdir(dir_name):
if os.listdir(dir_name):
submodule_initialized = True

if not submodule_initialized:
if not is_submodule_initialized('godot-cpp'):
print_error("""godot-cpp is not available within this folder, as Git submodules haven't been initialized.
Run the following command to download godot-cpp:
git submodule update --init --recursive""")
sys.exit(1)

env = SConscript("godot-cpp/SConstruct", {"env": env, "customs": customs})
env = SConscript("godot-cpp/SConstruct", {"env": local_env.Clone(), "customs": customs})
env.Append(
CPPPATH=["src/", "s7/"],
CPPDEFINES={
Expand All @@ -48,6 +71,7 @@ env.Append(

sources = [
Glob("src/*.cpp"),
Glob("src/repl/*.cpp"),
Glob("s7/s7.c")
]

Expand All @@ -58,20 +82,26 @@ if env["target"] in ["editor", "template_debug"]:
except AttributeError:
print("Not including class reference as we're targeting a pre-4.3 baseline.")

file = "{}{}{}".format(libname, env["suffix"], env["SHLIBSUFFIX"])
filepath = ""
file = "{}{}{}".format(lib_name, env["suffix"], env["SHLIBSUFFIX"])
file_path = ""

if env["platform"] == "macos" or env["platform"] == "ios":
filepath = "{}.framework/".format(env["platform"])
file = "{}.{}.{}".format(libname, env["platform"], env["target"])
file_path = "{}.framework/".format(env["platform"])
file = "{}.{}.{}".format(lib_name, env["platform"], env["target"])

libraryfile = "bin/{}/{}{}".format(env["platform"], filepath, file)
library_file = "bin/{}/{}{}".format(env["platform"], file_path, file)
library = env.SharedLibrary(
libraryfile,
library_file,
source=sources,
)

copy = env.InstallAs("{}/bin/{}/{}lib{}".format(projectdir, env["platform"], filepath, file), library)
copy = env.InstallAs("{}/bin/{}/{}lib{}".format(project_dir, env["platform"], file_path, file), library)

embed_scheme_repl = env.Command(
target="src/repl/gen/s7_scheme_repl_string.hpp",
source="demo/addons/s7/s7_scheme_repl.scm",
action=embed_file
)

default_args = [library, copy]
default_args = [embed_scheme_repl, library, copy]
Default(*default_args)
2 changes: 1 addition & 1 deletion demo/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ config_version=5

[application]

config/name="godot cpp template"
config/name="godot s7 scheme"
config/features=PackedStringArray("4.3", "Forward Plus")
config/icon="res://icon.svg"
1 change: 1 addition & 0 deletions emacs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.elc
42 changes: 42 additions & 0 deletions emacs/geiser-godot-s7-autoloads.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
;;; geiser-godot-s7-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; Generated by the `loaddefs-generate' function.

;; This file is part of GNU Emacs.

;;; Code:


;;;### (autoloads nil "geiser-godot-s7" "geiser-godot-s7.el" (0 0
;;;;;; 0 0))
;;; Generated autoloads from geiser-godot-s7.el

(autoload 'connect-to-godot-s7 "geiser-godot-s7" "\
Start a Godot s7 REPL connected to a remote process.
Start a Scheme Repl in the active Godot s7 scene." t)

(geiser-activate-implementation 'godot-s7)

(autoload 'run-godot-s7 "geiser-godot-s7" "\
Start a Geiser Godot s7 REPL." t)

(autoload 'switch-to-godot-s7 "geiser-godot-s7" "\
Start a Geiser Godot s7 REPL, or switch to a running one." t)

(register-definition-prefixes "geiser-godot-s7" '("geiser-godot-s7-" "godot-s7"))

;;;***

;;; End of scraped data

(provide 'geiser-godot-s7-autoloads)

;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End:

;;; geiser-godot-s7-autoloads.el ends here
Loading

0 comments on commit d514344

Please sign in to comment.