Skip to content
This repository has been archived by the owner on May 29, 2023. It is now read-only.

Latest commit

 

History

History
973 lines (836 loc) · 27.1 KB

dev-log.org

File metadata and controls

973 lines (836 loc) · 27.1 KB

<2020-06-22 Mon> adding s7

emacs related

(c-set-style "cc")

tcp socket / repl

options for the networking

  • sdl_net

nanomsg next generation (nng)

(nahh.. couldn’t use simple/dummy AF_INET socket)

huh! it reads everything into a buffer, don’t have to deal with that myself

char *   buf = NULL;
size_t   sz;
uint64_t val;
if ((rv = nng_recv(sock, &buf, &sz, NNG_FLAG_ALLOC)) != 0) {
 fatal("nng_recv", rv);
}      

NNG_FLAG_ALLOC

If this flag is present, then a “zero-copy” mode is used. In this case the caller must set the value of data to the location of another pointer (of type void *), and the sizep pointer must be set to a location to receive the size of the message body. The function will then allocate a message buffer (as if by nng_alloc()), fill it with the message body, and store it at the address referenced by data, and update the size referenced by sizep. The caller is responsible for disposing of the received buffer either by the nng_free() function or passing the message (also with the NNG_FLAG_ALLOC flag) in a call to nng_send().

s7 repl.scm

357aaa1 commit broke the libc_s7.c generation (last working commit 7fb147f)

but how does all this work?

;; cload.scm
(define *cload-c-compiler* (if (provided? 'gcc) "gcc" (if (provided? 'clang) "clang" "cc")))

s7 remote socket repl

example dumb repl

// s7.c
static void dumb_repl(s7_scheme *sc)
{
  while (true)
    {
      char buffer[512];
      fprintf(stdout, "\n> ");
      if (!fgets(buffer, 512, stdin)) break;  /* error or ctrl-D */
      if (((buffer[0] != '\n') || (strlen(buffer) > 1)))
	{
	  char response[1024];
	  snprintf(response, 1024, "(write %s)", buffer);
	  s7_eval_c_string(sc, response);
	}
    }
  fprintf(stdout, "\n");
  if (ferror(stdin))
    fprintf(stderr, "read error on stdin\n");
}  

returning char*, string etc, formatting strings

  • formatting
    #include <sstream>
    #include <iostream>
    
    
    std::ostringstream stream;
    stream << "Foo" << "bar" << std::endl;
    std::string str = stream.str();
        
  • returning strings
    // returning char*
    
    char* returnChar(){
      char* str = "blahblah";
      return str;
    }
    // BAD! I return a dangling pointer
    
    char* returnC_str(){
      std::string myString = "nice";
      return myString.c_str();
    }
    
    // BAD! again, dangling pointer
    
    char* returnHeapChar(){
      int lenght = 10;
      char * new_string = new char[length + 1]; // +1 for the terminating the string with 0
      std::string someString = "nice";
      std::strcpy(new:string, someString.c_str());
    }
    
    // OK! but I have to run delete myself
    
    std::string returnStr(){
      // all good, go wild
    }
        

c++ callbacks?

to use for the tcp server

Usage:

server.listen(1234, [](const char*) {
		      // doing something with data?
		    } )

https://stackoverflow.com/questions/20353210/usage-and-syntax-of-stdfunction

<2020-06-24 Wed> app & repl?

ninja -C build
./build/s7-imgui
(run-scheme "netcat localhost 1234")
netcat localhost 1234

repl problems

(display ;;as
 "hi" ;; 2nd line
 )

1

use read?

s7_pointer s7_read(s7_scheme *sc, s7_pointer port)
{
  if (is_input_port(port))
    {
      s7_pointer old_let;
      declare_jump_info();

      old_let = sc->curlet;
      sc->curlet = sc->nil;
      push_input_port(sc, port);

      store_jump_info(sc);
      set_jump_info(sc, READ_SET_JUMP);
      if (jump_loc != NO_JUMP)
	{
	  if (jump_loc != ERROR_JUMP)
	    eval(sc, sc->cur_op);
	}
      else
	{
	  push_stack_no_let_no_code(sc, OP_BARRIER, port);
	  push_stack_direct(sc, OP_EVAL_DONE);

	  eval(sc, OP_READ_INTERNAL);

	  if (sc->tok == TOKEN_EOF)
	    sc->value = eof_object;

	  if ((sc->cur_op == OP_EVAL_DONE) &&
	      (stack_op(sc->stack, s7_stack_top(sc) - 1) == OP_BARRIER))
	    pop_stack(sc);
	}
      pop_input_port(sc);
      sc->curlet = old_let;

      restore_jump_info(sc);
      return(sc->value);
    }
  return(simple_wrong_type_argument_with_type(sc, sc->read_symbol, port, an_input_port_string));
}   

Solution ?..

  • upon socket data, append to a string stream
  • try to “read” the current stream string
    • if it succeeds, perfect, just eval the string & emptry the stream
    • if not, just wait until the next chunk of data. store the reader error

upon new data, if there is pending error, but plenty of time (define ?) has passed, ignore the previous error and start reading from scratch. probably also send something to the connected client?

drawing from s7 draw function

  • mimic the processing nomenclature
    • (define (setup) .. )
    • (define (draw) .. )
  • ffi for the imgui functionality
    • bind them to s7

adding gtest

meson wrap install gtest

buttons to compile run etc

(button-lock-mode 1)
(defun button/compile ()
  "Shout when clicked"
  (interactive)
  (message "compiling")
  (comint-send-string "*s7-imgui*" "ninja -C build\r")
  )

(defun button/run ()
  "Shout when clicked"
  (interactive)
  (message "running")
  (comint-send-string "*s7-imgui*" "./build/s7-imgui\r")
  )

(defun button/stop ()
  "Shout when clicked"
  (interactive)
  (message "stop")
  (interrupt-process "*s7-imgui*" comint-ptyp)
  )

(defun button/test ()
  "Shout when clicked"
  (interactive)
  (message "stop")
  (comint-send-string "*s7-imgui*" "./build/test/gtest-all\r")
  )

(button-lock-set-button (regexp-quote ">compile")
			'button/compile
			:face 'link )

(button-lock-set-button (regexp-quote ">run")
			'button/run
			:face 'link )

(button-lock-set-button (regexp-quote ">stop")
			'button/stop
			:face 'link )

(button-lock-set-button (regexp-quote ">test")
			'button/test
			:face 'link )
  • >compile
  • >run
  • >stop
  • >test

writing an inc! function

(define (inc! x)
  (format #t "increasing x: ~A ~A" x (symbol->value x))
  ((outlet (curlet)) x)

  ;; (set! ((outlet (curlet)) x) 2)
;;  (set! x (+ 1 x))
  ;; (format #t "x is now ~A" x)
)

(define x 0)
(inc! x)
(inc! 'x)
(symbol? 'x)
(symbol->value 'x)
(inc! x)
x ;; x is still 0

check

> (set! (lt 'a) 12)

in the documentation

ielm repl window.. it always asks for window

  • exec-in-script is true for shell, it doesn’t ask anything
    (defun eir-repl-start (repl-buffer-regexp fun-repl-start &optional exec-in-script)
        

    in eir-eval-in-ielm add a last argument t to the eir-eval-in-repl-lisp call

r7rs.scm

windows? is it working?

in linux there is plenty of magic

  • generates a c file
  • compiles it
  • dynamically loads it

box

(let ((e (box 1)))
  (test (box? e) #t)
  (test (unbox e) 1)
  (test (e 'value) 1)
  (set-box! e 2)
  (test (unbox e) 2)
  (test (string=? (object->string e) "(inlet 'type box-type 'value 2)") #t))

<2020-06-28 Sun> building on windows

cannot get window with opengl

fixed in https://github.com/actonDev/SDL/commit/3e11ce100ef74d11ef57f7d1ee837d67c7e2ab2c in CMakeLists

if(SDL_VIDEO)
  if(VIDEO_OPENGL)
    set(SDL_VIDEO_OPENGL 1)
    set(SDL_VIDEO_OPENGL_WGL 1)
    set(SDL_VIDEO_RENDER_OGL 1)
    set(HAVE_VIDEO_OPENGL TRUE)
  endif()
endif()

see also subprojects/sdl2/premake/VisualC/VS2008/SDL_config_premake.h

#define SDL_VIDEO_DRIVER_WINDOWS 1
#define SDL_VIDEO_RENDER_OGL 1

   #endif
#ifndef SDL_VIDEO_RENDER_OGL
#define SDL_VIDEO_RENDER_OGL 1
#endif
#ifndef SDL_VIDEO_OPENGL
#define SDL_VIDEO_OPENGL 1
#endif
#ifndef SDL_VIDEO_OPENGL_WGL
#define SDL_VIDEO_OPENGL_WGL 1
#endif
#mesondefine SDL_VIDEO_RENDER_D3D11 // it's on in premake
#mesondefine SDL_VIDEO_RENDER_OGL // on premake

library: shared vs static

LINK : fatal error LNK1181: cannot open input file ‘..\subprojects\imgui-1.76\imgui.lib’

Solved by adding this in the project

project('s7-imgui', 'cpp', 'c',
	default_options: [
	  'default_library=static', # this fixed it
	]
       )   

the default_library=static did the trick

main function & windows

Windows wants a WinMain function

// https://stackoverflow.com/a/58819006/8720686
#ifdef _WIN32
int APIENTRY WinMain(HINSTANCE hInstance,
   HINSTANCE hPrevInstance,
   LPSTR lpCmdLine, int nCmdShow)
{
   return main(__argc, __argv);
}
#endif  

But, instead of that, if we link against the sdl2_main library, this is taken care of

opengl screenshot

https://stackoverflow.com/questions/5862097/sdl-opengl-screenshot-is-black#5867170

<2020-07-01 Wed> windows: cannot build

[3/16] Linking target examples/example_imgui.exe FAILED: examples/example_imgui.exe c++ @examples/example_imgui.exe.rsp c++.exe: error: winmm.lib: No such file or directory c++.exe: error: version.lib: No such file or directory c++.exe: error: imm32.lib: No such file or directory c++.exe: error: opengl32.lib: No such file or directory c++.exe: error: iphlpapi.lib: No such file or directory

aaah, aha! it was using gcc. not msvc

  • wipe
  • setup build –backend vs

checking windows compiler

added a check in meson.build

meson setup build-mingw
ninja -C build-mingw

<2020-07-01 Wed> todo list: more bindings, mutex [4/4]

bindings

wrote some ffi utils, creating c-objects and sharing between c<->scheme

TODO

  • slider
  • layout (same line

layout

check out the layout. how is it?

ImGui::SameLine();

create macro: m-horizontal

  • first element just gets drawn
  • subsequent elements have the same-line call prepended

scheme macros for begin

something like

(defmacro* imgui/m-window (:title title
				  :open open
				  ) . body
  `(begin
     (imgui/begin title open?)
     ,body
     (imgui/end)
     )
  )

ok, actual solution don’t know if I can use define-macro* and pass the rest . body

(define-macro (imgui/m-begin args . body)
  `(begin
     (imgui/begin ,@args)
     ,@body
     (imgui/end)))

(comment
 (macroexpand (imgui/m-begin ("test" 'the-c-object)
			     (imgui/text "hi")
			     (imgui/text "scheme s7")
			     ))
 ;; =>
 (begin (imgui/begin "test" 'the-c-object) (imgui/text "hi") (imgui/text "scheme s7") (imgui/end))
 
 )

yup, I can use it

(define-macro* (imgui/m-begin2 (title "") (*open #t) :rest body)
  (if (eq? #t *open)
      `(begin
	 (imgui/begin ,title)
	 ,@body
	 (imgui/end))
      `(begin
	 (imgui/begin ,title ,*open)
	 ,@body
	 (imgui/end))))

(comment
 (macroexpand (imgui/m-begin2 :title "always open"
			      (imgui/text "hi")
			      (imgui/text "scheme s7")
			      ))
 ;; =>
 (begin (imgui/begin "always open" (imgui/text "hi")) (imgui/text "scheme s7") (imgui/end))

 (macroexpand (imgui/m-begin2 :title "always open"
			      :*open 'the-c-object
			      (imgui/text "hi")
			      (imgui/text "scheme s7")
			      ))
 ;; =>
 (begin (imgui/begin "always open" 'the-c-object) (imgui/text "hi") (imgui/text "scheme s7") (imgui/end))
 )

I prefer the simpler, first version

mutex

I can crash the application when sending quickly from the repl the (draw) definition. expected :)

  • use a mutex around the main loop

s7 ffi: free functions

delete void* isn’t very smart.. fix this :) but.. why wasn’t the compiler complaining??

oor.. could be that for internal types it’s ok.hmm..

gc in float_arr not called

S7 doesn’t have a precise garbage collector

updated the test, indeed the free gets called

gfx like calls

  • circle
  • line
  • text
  • triangle
  • ..etc

org-mode literate programming: creating foreign types

Drawing (gfx style)

see

make a call style like SDL2_gfxPrimitives.h

  • circleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint32 color);
  • filledCircleColor(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 r, Uint32 color);

or like https://learn.adafruit.com/adafruit-gfx-graphics-library/graphics-primitives

ImVec2 p = ImGui::GetCursorScreenPos();

ImDrawList *draw_list = ImGui::GetWindowDrawList();
float cx = 0;
float cy = 0;
float r = 50;
float thickness = 2;
float line_height = ImGui::GetTextLineHeight();
ImGuiStyle &style = ImGui::GetStyle();
//    style.ItemInnerSpacing.y
ImGui::Dummy(
     ImVec2(2 * r + style.ItemInnerSpacing.x,
	    2 * r + style.ItemInnerSpacing.y));

int segments = 16;
ImU32 col32line = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);

draw_list->AddCircle(ImVec2(p.x + cx + r, p.y + cy + r), r, col32line, 32,
		     thickness);

C++17

meson configure build -Dcpp_std=c++17 (it has the cool filesystem/path libs)

open file dialog

https://github.com/mlabbe/nativefiledialog

ItemGroup>
    <ClInclude Include="..\..\src\common.h" />
    <ClInclude Include="..\..\src\include\nfd.h" />
    <ClInclude Include="..\..\src\nfd_common.h" />
    <ClInclude Include="..\..\src\simple_exec.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="..\..\src\nfd_common.c" />
    <ClCompile Include="..\..\src\nfd_win.cpp" />
  </ItemGroup>  
$(OBJDIR)/nfd_common.o: ../../src/nfd_common.c
	@echo $(notdir $<)
	$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/nfd_gtk.o: ../../src/nfd_gtk.c
	@echo $(notdir $<)
	$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"

C++ private functions, hiding implentation from header etc

https://stackoverflow.com/a/28734794

<2020-07-12 Sun> s7 bug

Done

Thanks for the bug report. This is actually a bug in the documentation – the array of names should be sorted alphabetically, but I forgot to mention that in s7.html.

sent to the mailing list

TEST(s7_environments, autoloads_bug) {
    const char *autoloads[6] = {
        // each pair of entries is entity name + file name
        "aod.lib1", "aod/lib1.scm", //
        "aod.lib2", "aod/lib2.scm", //
        "aod.extra.foo", "aod/extra/foo.scm",
    };

    s7_scheme* sc1 = s7_init();
    s7_autoload_set_names(sc1, autoloads, 3);
    char* sexp = "(begin "
                 "(require aod.lib1)"
                 "(require aod.lib2)"
                 "1)";
    // ok that works
    ASSERT_EQ(1, s7_integer(s7_eval_c_string(sc1, sexp)));

    s7_scheme* sc2 = s7_init();
    s7_autoload_set_names(sc2, autoloads, 3);
    char* sexp2 = "(begin "
                  "(require aod.extra.foo)"
                  "2)";
    // THAT FAILS!!
    ASSERT_EQ(2, s7_integer(s7_eval_c_string(sc2, sexp2)));
    /**
     * ----------
    ;require: no autoload info for aod.extra.foo
    ; (require aod.extra.foo)
    ; ((lambda (hook lst) (if (do ((p lst (cdr ...
    ; (2)
    * -----------
    */
}  

some macros about clj style require

(define-macro* (aod/-require-bindings lib-exports as)
  (format *stderr* "=> require bindings ~A as ~A\n" lib-exports as)
  (let* ((as (or as lib-exports))
	 (prefix (symbol->string as)))
    ;; note: if I used a let inside the ` block, the (curlet) would refer to the let closure
    ;; thus, making any let assignments outside of the macro
    `(apply varlet (curlet)
	   (map (lambda (binding)
		  (let ((new-binding (string->symbol 
				      (string-append ,prefix "/" (symbol->string (car binding))))))
		    (format *stderr* "binding ~A\n" new-binding)
		    (cons new-binding 
			  (cdr binding))))
		,lib-exports))))
(define-macro* (aod/-require-as autoload-symbol (as #f))
    (format *stderr* "=> require autoload symbol ~A as ~A\n" autoload-symbol as)
  (let* ((as (or as autoload-symbol))
	 (prefix (symbol->string as)))
    `(apply varlet (curlet)
	    (with-let (unlet)
		      (let ()
			(require ,autoload-symbol)
			(map (lambda (binding)
			       (let ((new-binding (string->symbol 
						   (string-append ,prefix "/" (symbol->string (car binding))))))
				 (format *stderr* "binding ~A\n" new-binding)
				 (cons new-binding 
				       (cdr binding))))
			     (curlet)))))))  

eventually replaced from

(define-macro* (aod/require what (as #f))
  (let ((prefix (symbol->string `,(or as what))))
    ;; (format *stderr* "aod/require ~A :as ~A\n" what prefix)
    (if (defined? what)
	;; bindings from c
	(begin
	  ;; (format *stderr* "requiring foreign bindings ~A as ~A\n" what prefix)
	  `(apply varlet (curlet)
		  (map (lambda (binding)
		  (let ((new-binding (string->symbol 
				      (string-append ,prefix "/" (symbol->string (car binding))))))
		    (format *stderr* "binding ~A\n" new-binding)
		    (cons new-binding 
			  (cdr binding))))
		,what)))
	;; normal autload, symbol "what" not present
	(begin
	  ;; (format *stderr* "requiring autoload symbol ~A as ~A, features ~A\n autoload ~A\n" what prefix *features* (*autoload* what))
	  (if (defined? (string->symbol (string-append prefix "/*features*")))
	    (format *stderr* "WARNING: ~A already required as ~A\n" what prefix)
	    `(apply varlet (curlet)
		    (with-let (unlet)
			      (let ()
				;; note: we use load cause if we required already nothing will happen!
				;; (*autoload* ',what) gives us the file name
				(load (*autoload* ',what) (curlet))
				(map (lambda (binding)
				       (let ((new-binding (string->symbol 
							   (string-append ,prefix "/" (symbol->string (car binding))))))
					 (format *stderr* "binding ~A\n" new-binding)
					 (cons new-binding 
					       (cdr binding))))
				     (curlet))))))))))  

… new version

(define-macro* (aod/require what (as #f))
  (let* ((prefix (symbol->string `,(or as what)))
	(features-symbol (string->symbol (string-append prefix "/*features*"))))
    (format *stderr* "prefix ~A features ~A\n" prefix (string->symbol (string-append prefix "/*features*")))
    `(if (defined? ',features-symbol)
	(format *stderr* "WARNING: ~A already required as ~A\n" ',what ,prefix)
	;; else, doing the bidings:
	(if (defined? ',what)
	    ;; bindings from c
	    (apply varlet (curlet)
		   (map (lambda (binding)
			  (let ((binding-symbol (string->symbol 
						 (string-append ,prefix "/" (symbol->string (car binding))))))
			    (cons binding-symbol 
				  (cdr binding))))
			,what))
	     ;; normal autload, symbol "what" not present
	    (apply varlet (curlet)
		   (with-let (unlet)
			     (let ()
			       ;; note: we use load cause if we required already nothing will happen!
			       ;; (*autoload* ',what) gives us the file name
			       (load (*autoload* ',what) (curlet))
			       (map (lambda (binding)
				      (let ((binding-symbol (string->symbol 
							     (string-append ,prefix "/" (symbol->string (car binding))))))
					(cons binding-symbol 
					      (cdr binding))))
				    (curlet)))))))))  

<2020-07-17 Fri> (ns ..) forms, switch namespace from emacs

created the src/scheme/aod/ns.scm for dealing with namespaces some 160 lines including plenty of comments. hope it will serve well.

See more in docs/s7.org

aod.c.imgui-sdl bindings

to quickly prototype with imgui. the window creation and imgui drawing is done from scheme, i’m not called by c.

example

(ns imgui-sratch)

(ns-require aod.c.imgui-sdl :as igsdl)
(ns-require aod.c.imgui :as ig)
(ns-require aod.imgui.macros :as igm)

(define *ctx* (igsdl/setup 400 400))

(define (draw)
  (igsdl/prepare *ctx*)

  ;; your drawing logic here
  ;; eg
  (igm/maximized
   ("imgui scratch")
   (ig/text "hi devil")
   (ig/text ""))

  
  (igsdl/flush *ctx*)
  )

;; drawing upon first running
(draw)

(comment
 ;; run destroy to kill the sdl window
 (igsdl/destroy *ctx*)
 )

<2020-07-23 Thu> building on windows: fail

error C2039: ‘filesystem’: is not a member of ‘std’ [W:\dev\actondev\s7-imgui\build\src\aod\7bbcc5b@@aod@sta.vcxproj]

filesystem path c_str()

‘s7_pointer s7_add_to_load_path(s7_scheme *,const char *)’: cannot convert argument 2 from ‘const std::filesystem::path::value_type *’ to ‘const char *’

aha. on linux path.c_str() returns char*, but on windows it’s w_char .. ughh

Solution:

path.string().c_str()

VS and c++17

meson configure build | grep std # it's indeed c++17

solution (for aod lib)

cpp_args = []
system = host_machine.system()
if system == 'windows'
  cpp_args += '/std:c++17'
endif

aod_lib = library(
  'aod',
  # sources: aod_sources,
  include_directories: include_directories('..'),
  sources: aod_sources,
  cpp_args: cpp_args,
  # ...
  )
   

or..

aod_lib = library(
  'aod',
  cpp_std: 'c++17',
  # ..
  )

uhmmm.

subprojects\s7_imgui\src\aod\meson.build:44: WARNING: Passed invalid keyword argument “cpp_std”.

meson -v
pip3 install meson --upgrade
# hm updated from 0.54.3 to 0.55

hm.. now it works..?

drawing arc/bezier

IMGUI_API void  AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0);
  

memoize, performance

In the first working demo of s7vst, the full each frame drawing was using ~11% cpu

but with

;; in aod/sxs.scm
(set! lines (memoize lines))

Cpu is around ~5%

hooray :D

imgui.. ImDrawList cache?

Could I maybe cache certaing components? How I imagine it:

  • define-imgui or something
  • uses its own drawlist on each call
  • invalidates the drawlist if there is a mouse event or something..

s7 & opengl shaders?

Saw a demo of using a shader with iPlug2 in oli larkin’s talk (creator of iPlug)

Wonder how easy (or not) would be to do something similar with s7

Dilambdas

(define (make-file-contents *char)
  ;; dilambda is a quick way to define getters and setters
  (dilambda
   ;; getter
   (lambda ()
     (*char))
   (lambda (v)
     (if (< buffer-size (length v))
	 (print "text bigger than buffer-size!")
	 (begin
	   (set! (*char) v))))))

(define *file-contents* (make-file-contents *buffer))  

emacs-lisp

Removed it, but it’s nice to keep

(let ((build-res (with-temp-buffer
		   (call-process "ninja" nil t t "-C" "build"))))
  (if (= 0 build-res)
      (progn
	;; (message "OK! running scheme")
	(let ((default-directory (projectile-project-root)))
	  (run-scheme (concat (projectile-project-root) "build/repl " file))
	  ))
    (progn
      ;; (message "build failed")
      (message (buffer-string))
      )))

<2020-08-03 Mon> imgui input-text and char*

the “bug” that I stumbled in the video

// Edit a string of text
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
//   This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
//   Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator.
// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect.
// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h
// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are
//  doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188)
bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data)
{  

When active, hold on a privately held copy of the text (and apply back to ‘buf’). So changing ‘buf’ while the InputText is active has no effect.

ns-doc all namespaces, create documentation files

probably with emacs & org mode.. :)

<2020-08-03 Mon> let’s try to do that