Skip to content

Commit

Permalink
Introduce nREPL control panel add on
Browse files Browse the repository at this point in the history
  • Loading branch information
ikappaki committed Nov 6, 2024
1 parent 67f63d3 commit 521b900
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 40 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Updated create nREPL control panel fn to return a fn that can destroy it.
- Created a script to generate the nREPL control panel add-on.

## 0.2.0

- Added async server interface support in `start-server!` with a client work abstraction.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "basilisp-blender"
version = "0.2.0"
version = "0.3.0a9"
description = ""
authors = ["ikappaki"]
readme = "README.md"
Expand Down
47 changes: 47 additions & 0 deletions scripts/bb_addon_create.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from basilisp_blender import control_panel_create
bl_info = {
"name" : "Basilisp Blender Add On",
"author" : "ikappaki",
"version" : (0, 99, 99),
"blender" : (3, 60, 0),
"category": "Development",
}
_DESTROY_FN = None
def register():
global _DESTROY_FN
print(f"nREPL Control Panel creating...")
_DESTROY_FN = control_panel_create()
print(f"nREPL Control Panel creating... done")

def unregister():
global _DESTROY_FN
print("nREPL Control Panel destroying...")
_DESTROY_FN()
_DESTROY_FN = None
print("nREPL Control Panel destroying... done")

if __name__ == '__main__':
# This script should be invoked from the project root directory.
#
# Copies the contents of this file up to, but not including, the
# __main__ section to 'dist/nrepl_panel_addon_<version>.py'.
# Replaces the bl_info.version above with the major.minor.patch
# <version> numbers as reported by `poetry version`.
re = __import__("re")
subprocess = __import__("subprocess")
result = subprocess.run(["poetry", "version"], capture_output=True, text=True)
_, version = result.stdout.split(" ")
major, minor, patch = version.split(".")
patch_int = int(re.match(r'^\d+', patch).group())
filename_dist = f'dist/nrepl_panel_addon_{version.strip().replace(".", "_")}.py'
version_mark = "(0, 99, 99)"
with open(__file__, 'r') as src:
with open(filename_dist, 'w', newline="\n") as dst:
dst.write(f"# Autogenerated from {__file__}\n")
for line in src.readlines():
if line.strip().startswith("if __name__ == '__main__':"):
break
if version_mark in line:
line = line.replace(version_mark, f"({major}, {minor}, {patch_int})")
dst.write(line)
print(f":bb_addon_create.py :created {filename_dist}")
13 changes: 10 additions & 3 deletions src/basilisp_blender/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from basilisp import main as basilisp
from basilisp.lang import compiler
from basilisp.lang.keyword import Keyword
from basilisp.lang.util import munge

COMPILER_OPTS = compiler.compiler_opts()
Expand All @@ -13,7 +14,6 @@
LOGGER = logging.getLogger("basilisp-blender")
LOGGER.addHandler(logging.StreamHandler())


def log_level_set(level, filepath=None):
"""Sets the logger in the `LOGGER` global variable to the
specified `level`.
Expand All @@ -31,6 +31,13 @@ def log_level_set(level, filepath=None):
# log_level_set(logging.DEBUG, "basilisp-blender.log")

def control_panel_create():
"""Initialises and displays the nREPL server UI control panel."""
"""Initialises and displays the nREPL server UI control panel. It
returns a function to destroy the panel and settings, and stop the
server if it is running.
"""
ctrl_panel_mod = importlib.import_module(munge("basilisp-blender.control-panel"))
ctrl_panel_mod.nrepl_control_panel_create__BANG__()
panel = ctrl_panel_mod.nrepl_control_panel_create__BANG__()
return panel[Keyword("destroy!")]


50 changes: 30 additions & 20 deletions src/basilisp_blender/control_panel.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@
os.path
sys))

(defn- class-register!
"Helper function to register a bpy class, with prior unregistering if
possible."
[class]
(try
(.unregister-class bpy/utils class)
(catch Exception e
nil))
(.register-class bpy/utils class))

(defn- nrepl-url
[host port]
(str "nrepl://" host
Expand Down Expand Up @@ -253,7 +243,14 @@
"Creates the nrepl server control panel in Blender, and returns its
control interface.
The user settings are stored in the Scene as Properties."
The user settings are stored in the Scene as Properties.
It returns a map with the following entries
:ctrl The server control instance.
:destroy! A function that destroys the panel and settings, and
stops the server if it is running."
[]
(let [ctrl (ctrl-make)
settings-user
Expand All @@ -265,16 +262,29 @@
panel
(nrepl-control-panel-class-make ctrl)]


(class-register! settings-user)
(bpy.utils/register-class settings-user)
(set! bpy.types.Scene/nrepl-settings-user (.PointerProperty bpy/props ** :type settings-user))
(class-register! operator)
(class-register! panel)

ctrl))
(bpy.utils/register-class operator)
(bpy.utils/register-class panel)

{:ctrl ctrl
:destroy! (fn nrepl-control-panel-destroy! []
(binding [*out* sys/stdout]
(doseq [cls [settings-user operator panel]]
(try
(bpy.utils/unregister-class cls)
(catch Exception e
nil)))
(delattr bpy.types/Scene "nrepl_settings_user")
(let [{:keys [result] :as _info} (ctrl-do! ctrl :info-get)
{:keys [status]} result]
(when (= status [:serving])
(ctrl-do! ctrl :server-toggle!))))
nil)}))

(comment
(def ctrl2 (nrepl-control-panel-create))
@ctrl2
;;
(def ctrl2 (nrepl-control-panel-create!))
@(:ctrl ctrl2)
( (:destroy! ctrl2))
;;
)
42 changes: 26 additions & 16 deletions tests/basilisp_blender/integration/control_panel_test.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,21 @@
(require '[basilisp-blender.control-panel :as p])

;; this var will be used throughout all other tests
(def ctrl-test (p/nrepl-control-panel-create!))
(def ctrl-panel (p/nrepl-control-panel-create!))
(def ctrl-test (:ctrl ctrl-panel))
(def ctrl-destroy! (:destroy! ctrl-panel))

@ctrl-test)]
(is (= {:res {:status [:ready]}} result)))

(is (= {:result {:host nil :status [:ready] :port nil :port-dir nil}}
(:res (but/with-client-eval!
(p/ctrl-do! ctrl-test :info-get nil))))))
(p/ctrl-do! ctrl-test :info-get))))))

(testing "server start/stop without options"
(let [{:keys [res] :as ret} (but/with-client-eval!
[(p/ctrl-do! ctrl-test :server-toggle! nil)
(p/ctrl-do! ctrl-test :info-get nil)])
[(p/ctrl-do! ctrl-test :server-toggle!)
(p/ctrl-do! ctrl-test :info-get)])
[[toggle-state toggle-msg :as toggle] info] (map :result res)]
(is (= :started toggle-state))
(let [{:keys [port]} info
Expand All @@ -40,8 +42,8 @@

;; toggle -- server stop
(let [{:keys [res] :as ret} (but/with-client-eval!
[(p/ctrl-do! ctrl-test :server-toggle! nil)
(p/ctrl-do! ctrl-test :info-get nil)])
[(p/ctrl-do! ctrl-test :server-toggle!)
(p/ctrl-do! ctrl-test :info-get)])
[[toggle-state toggle-msg :as toggle] info] (map :result res)]
(is (= :stopped toggle-state) ret)
(is (= (str "nrepl://127.0.0.1:" port) toggle-msg) toggle)
Expand All @@ -59,17 +61,17 @@

;; toggle -- server stop
(let [{:keys [res] :as ret} (but/with-client-eval!
[(p/ctrl-do! ctrl-test :server-toggle! nil)
(p/ctrl-do! ctrl-test :info-get nil)])
[(p/ctrl-do! ctrl-test :server-toggle!)
(p/ctrl-do! ctrl-test :info-get)])
[[toggle-state toggle-msg :as toggle] info] (map :result res)]
(is (= :stopped toggle-state))
(is (= (str "nrepl://0.0.0.0:" port) toggle-msg) toggle)
(is (= {:host nil :status [:ready] :port nil :port-dir nil} info))))))

(testing "server port option"
(let [{:keys [res] :as ret} (but/with-client-eval!
[(p/ctrl-do! ctrl-test :server-toggle! {:port -1})
(p/ctrl-do! ctrl-test :info-get)])]
(let [{:keys [res] :as _ret} (but/with-client-eval!
[(p/ctrl-do! ctrl-test :server-toggle! {:port -1})
(p/ctrl-do! ctrl-test :info-get)])]
(is [{:error
(:server-make-error
[:type-of
Expand All @@ -78,25 +80,33 @@
{:result {:port nil, :host nil, :status [:ready], :port-dir nil}}] res)))

(testing "server nrepl-port-dir option"
(let [{:keys [exc res] :as ret}
(let [{:keys [exc res] :as _ret}
(but/with-client-eval!
(import tempfile)
(with [tmpdir (tempfile/TemporaryDirectory)]
{:actions
[(p/ctrl-do! ctrl-test :server-toggle! {:nrepl-port-dir tmpdir})
(p/ctrl-do! ctrl-test :info-get)
(p/ctrl-do! ctrl-test :server-toggle! nil)]
(p/ctrl-do! ctrl-test :server-toggle!)]
:tmpdir tmpdir}))

{:keys [actions tmpdir]} res

[[toggle-state] {:keys [port-dir]} [toggle-state2]]
(map :result actions)
(map :result actions)]

]
(is (nil? exc) exc)
(is (= :started toggle-state))
(is (= tmpdir port-dir) res)
(is (= :stopped toggle-state2))))))
(is (= :stopped toggle-state2))))

(testing "destroying panel"
(let [{:keys [res]} (but/with-client-eval!
[(p/ctrl-do! ctrl-test :server-toggle!)
(ctrl-destroy!)
(p/ctrl-do! ctrl-test :info-get)])
[[toggle-state] _ {:keys [status] :as _info}] (map :result res)]
(is (= :started toggle-state))
(is (= [:ready] status) _info)))))

#_(tu/pp-code (panel-control-test))

0 comments on commit 521b900

Please sign in to comment.