actondev / s7-imgui

Using s7 scheme alongside Dear ImGui to (interactively) build (cross platform) GUI apps.
40 stars 4 forks source link

Namespaces #3

Open actondev opened 4 years ago

actondev commented 4 years ago

This issue is meant for organization/documentation purposes.

As s7 scheme doesn't have any separate module/namespace structure, coming from clojure I really missed this feature. So I cam up with a solution. See https://github.com/actonDev/s7-imgui/blob/b59927d/src/scheme/aod/ns.scm at the time of writing

Example usage:

(ns foo.bar)
;; sets the *ns* symbol in a new environment (let)
;; subsequent calls are evaluated in this environment
;; this is done by the repl from the c side. see
;; https://github.com/actonDev/s7-imgui/blob/b59927d2c875ff713aeddc8476973e8329e6f802/src/aod/s7/repl.cpp#L39

(ns-require foo.bar2)
(ns-require foo.bar3 :as bar3)
;; fully qualified namespace for calling
(foo.bar2/hi)

;; call with alias
(bar3/hi)

;; shows the current namespace
*ns*

;; the following are equivalent
;; --- BEGIN equivalent
(with-ns foo.bar2
     (hi))

;; *nss* mnemonic: plurar of ns. NameSpaceS
(with-let (*nss* 'foo.bar2)
      (hi))
;; this changes the *ns*
(ns foo.bar2)
(hi)
;; ---- END equivalent

;; WARNING
;; now foo.bar2/hi and bar3/hi are NOT available
;; to make them available we have to switch back:
(ns foo.bar)
actondev commented 4 years ago

This makes the following scenario possible

This is done like this:

TODO

For that benchmark see https://github.com/actonDev/s7-imgui/blob/0.1.0/test/scheme/test-benchmark.scm the gist: calling (fib 5) 1000000 times

The dynamic version:
ns-require: Time fib 5 times x 1000000 (#t 1.686106) 

The native scheme require version:
require: Time fib 5 times x 1000000 (#t 0.8520600000000003) 

The ns-require but with :dynamic #f version
ns-require :dynamic #f : Time fib 5 times x 1000000 (#t 0.8458799999999997) 
actondev commented 4 years ago

Emacs bindings for switching namespaces, evaluating sexp under current namespace

;; Some helper funcionts for workin with s7 namely, changing
;; "namespace" with (ns ..) forms ala clojure tyle
;; 
;; Pardon the non-elisp-idiomatic dots and slashes but I really prefer
;; this namespace/clojure sytnax

(require 'cmuscheme)

(defun aod.s7/get-ns ()
  "Get the namespace name to send on the repl.
NOTE: you need to have the (ns) in the beginning of the
line. This is to not mistake things after ;; comments"
  (save-excursion
    (beginning-of-buffer)
    (if (re-search-forward "^\(ns \\([a-zA-Z0-9\.\-]+\\)" nil t)
    (match-string-no-properties 1)
      nil)))

(defun aod.s7/switch-to-ns ()
  "Switches to the namespace of the currently open buffer."
  (interactive)
  (if-let ((ns (aod.s7/get-ns)))
      (progn
    (message (format "switching to ns %s" ns))
    (scheme-send-string (format "(ns %s)" ns)))
    ;; else
    (progn
      (message "switching to (rootlet)")
      (scheme-send-string "(set! *ns* (rootlet))"))))

(defun aod.s7/top-level-sexp ()
  "Gets the top level sexp without any trailing new lines"
  (save-excursion
    (end-of-defun)
    (let ((end (point)))
      (beginning-of-defun)
      (string-trim
       (buffer-substring-no-properties (point) end)))))

(defun aod.s7/send-definition ()
  "Sends the top level sexp under point.
Note: (scheme-send-definition) would send 2 things:
1. The top level sexp with a new line at the end (cause of (end-of-defun))
2. The '\n' string as well. (extra commint command)

Here we just send ounce the trimmed top level sexp"
  (interactive)
  (aod.s7/switch-to-ns)
  (scheme-send-string
   (aod.s7/top-level-sexp)))

(defun aod.s7/send-last-sexp ()
  "Send the last sexp"
  (interactive)
  (aod.s7/switch-to-ns)
  (scheme-send-last-sexp)
  )

(provide 'aod-s7)

Then, to use it:

(use-package aod-s7
  :load-path "elisp/" ;;wherever the above .el files resides
  ;; the after apparently is needed..
  ;; if not, the bindings are not there even if in a scheme file
  ;; and having started a scheme with (run-scheme)
  :after (cmuscheme)
  :bind(
    :map scheme-mode-map
    ("C-<return>" . aod.s7/send-definition)
    ("M-<return>" . aod.s7/send-last-sexp)
    )
  )

That binds the

actondev commented 4 years ago

Updates:

Example:

(ns rootlet
    :require ((aod.c.foreign :as c)
          (aod.c.imgui :as ig)
          (aod.imgui.macros :as igm)
          (aod.c.nfd)
          (aod.c.imgui.window-flags :as igw)))
actondev commented 4 years ago

Update:

example usage

(ns aod.imgui.macros
    :doc "Some macros to make life easier while working with ImGui.
The usual syntax is (args . body)
- args are applied to corresponding raw imgui function
- body is executed either in a when block (eg when a menu items is active)
  or wrapped between the begin/end calls"
    :require
    ((aod.c.imgui :as ig)))

This is used to generate the documentation. see https://github.com/actonDev/s7-imgui/blob/master/docs/ns-doc.md