ede14d36bccb — Leonard Ritter 10 days ago
* renamed `sc_prompt_*` API functions
* removed `sc_set_autocomplete_scope`
* prefixed all prompt relevant API functions with `sc_prompt_*`
* added support for prompt autocompletion callback
* console: use autocompletion callback to implement scope completion
4 files changed, 53 insertions(+), 28 deletions(-)

M include/scopes/scopes.h
M lib/scopes/console.sc
M lib/scopes/core.sc
M src/globals.cpp
M include/scopes/scopes.h +7 -3
@@ 146,6 146,7 @@ SCOPES_TYPEDEF_RESULT_RAISES(sc_bool_i32
 typedef sc_valueref_raises_t (*sc_ast_macro_func_t)(sc_valueref_t);
 typedef sc_valueref_raises_t (*sc_typecast_func_t)(sc_valueref_t, const sc_type_t *);
 typedef sc_list_scope_raises_t (*sc_syntax_wildcard_func_t)(const sc_list_t *, const sc_scope_t *);
+typedef void (*sc_autocomplete_func_t)(const char *, void *);
 
 // booting
 

          
@@ 287,9 288,12 @@ SCOPES_LIBEXPORT sc_valueref_raises_t sc
 
 SCOPES_LIBEXPORT const sc_string_t *sc_default_styler(sc_symbol_t style, const sc_string_t *str);
 SCOPES_LIBEXPORT sc_bool_string_tuple_t sc_prompt(const sc_string_t *s, const sc_string_t *pre);
-SCOPES_LIBEXPORT void sc_save_history(const sc_string_t *path);
-SCOPES_LIBEXPORT void sc_load_history(const sc_string_t *path);
-SCOPES_LIBEXPORT void sc_set_autocomplete_scope(const sc_scope_t* scope);
+SCOPES_LIBEXPORT void sc_prompt_save_history(const sc_string_t *path);
+SCOPES_LIBEXPORT void sc_prompt_load_history(const sc_string_t *path);
+SCOPES_LIBEXPORT void sc_prompt_set_autocomplete_handler(sc_autocomplete_func_t func);
+SCOPES_LIBEXPORT void sc_prompt_add_completion(void *ctx, const char *text);
+SCOPES_LIBEXPORT void sc_prompt_add_completion_from_scope(void *ctx, const char *searchtext, const sc_scope_t* scope);
+
 SCOPES_LIBEXPORT const sc_string_t *sc_format_message(const sc_anchor_t *anchor, const sc_string_t *message);
 SCOPES_LIBEXPORT void sc_write(const sc_string_t *value);
 

          
M lib/scopes/console.sc +17 -4
@@ 50,7 50,7 @@ case (global-scope, show-logo : bool = f
     let eval-scope = (Scope global-scope)
 
     if (not (empty? history-path))
-        sc_load_history history-path
+        sc_prompt_load_history history-path
 
     sugar help ((value as Symbol))
         let val =

          
@@ 118,8 118,21 @@ case (global-scope, show-logo : bool = f
                 typedef (do "Enter 'exit;' or Ctrl+D to exit")
                     inline __typecall () (if true (exit 0))
 
+    global autocomplete-scope : Scope
+    fn autocomplete (text ctx)
+        # Tab on an empty string gives an indentation
+            TODO: is this really necessary anymore?
+        if ((@ text) == 0)
+            sc_prompt_add_completion ctx "    "
+            return;
+        if ((deref autocomplete-scope) != null)
+            sc_prompt_add_completion_from_scope ctx text autocomplete-scope
+        ;
+
     loop (preload cmdlist counter eval-scope = "" "" 0 eval-scope)
-        set-autocomplete-scope! eval-scope
+        autocomplete-scope = eval-scope
+
+        sc_prompt_set_autocomplete_handler autocomplete
 
         fn make-idstr (counter)
             .. "$" (tostring counter)

          
@@ 130,7 143,7 @@ case (global-scope, show-logo : bool = f
                 default-styler style-comment "►"
         let promptlen = ((countof idstr) + 2:usize)
         let success cmd =
-            __prompt
+            sc_prompt
                 ..
                     if (empty? cmdlist) promptstr
                     else

          
@@ 138,7 151,7 @@ case (global-scope, show-logo : bool = f
                     " "
                 preload
         if (not (empty? history-path))
-            sc_save_history history-path
+            sc_prompt_save_history history-path
         if (not success)
             return;
         fn endswith-blank (s)

          
M lib/scopes/core.sc +0 -2
@@ 6601,8 6601,6 @@ let
     realpath = sc_realpath
     globals = sc_get_globals
     set-globals! = sc_set_globals
-    __prompt = sc_prompt
-    set-autocomplete-scope! = sc_set_autocomplete_scope
     exit = sc_exit
     launch-args = sc_launch_args
     set-signal-abort! = sc_set_signal_abort

          
M src/globals.cpp +29 -19
@@ 349,39 349,43 @@ sc_bool_string_tuple_t sc_prompt(const s
     return { true, String::from_cstr(r) };
 }
 
-void sc_save_history(const sc_string_t *path) {
+void sc_prompt_save_history(const sc_string_t *path) {
     using namespace scopes;
     linenoiseHistorySave(path->data);
 }
 
-void sc_load_history(const sc_string_t *path) {
+void sc_prompt_load_history(const sc_string_t *path) {
     using namespace scopes;
     linenoiseHistoryLoad(path->data);
 }
 
 namespace scopes {
 
-static const Scope *autocomplete_scope = nullptr;
+static sc_autocomplete_func_t autocomplete_handler = nullptr;
 
 static void prompt_completion_cb(const char *buf, linenoiseCompletions *lc) {
-    // Tab on an empty string gives an indentation
-    if (*buf == 0) {
-        linenoiseAddCompletion(lc, "    ");
-        return;
-    }
-
-    const String* name = String::from_cstr(buf);
-    Symbol sym(name);
-    const Scope *scope = autocomplete_scope ? autocomplete_scope : globals;
-    for (const auto& m : scope->find_elongations(sym))
-        linenoiseAddCompletion(lc, m.name()->data);
+    if (autocomplete_handler)
+        autocomplete_handler(buf, lc);
 }
 
 }
 
-void sc_set_autocomplete_scope(const sc_scope_t* scope) {
+void sc_prompt_set_autocomplete_handler(sc_autocomplete_func_t func) {
     using namespace scopes;
-    autocomplete_scope = scope;
+    autocomplete_handler = func;
+}
+
+void sc_prompt_add_completion(void *ctx, const char *text) {
+    linenoiseAddCompletion((linenoiseCompletions *)ctx, text);
+}
+
+void sc_prompt_add_completion_from_scope(void *ctx, const char *searchtext, const sc_scope_t* scope) {
+    using namespace scopes;
+    const String* name = String::from_cstr(searchtext);
+    Symbol sym(name);
+    scope = scope ? scope : globals;
+    for (const auto& m : scope->find_elongations(sym))
+        linenoiseAddCompletion((linenoiseCompletions *)ctx, m.name()->data);
 }
 
 const sc_string_t *sc_format_message(const sc_anchor_t *anchor, const sc_string_t *message) {

          
@@ 2301,6 2305,9 @@ void init_globals(int argc, char *argv[]
     const Type *TYPE_typecast_func = native_ro_pointer_type(
         raising_function_type(TYPE_ValueRef, { TYPE_ValueRef, TYPE_Type }));
 
+    const Type *TYPE_autocomplete_func = native_ro_pointer_type(
+        function_type(_void, { rawstring, voidstar }));
+
     DEFINE_EXTERN_C_FUNCTION(sc_compiler_version, arguments_type({TYPE_I32, TYPE_I32, TYPE_I32}));
     DEFINE_EXTERN_C_FUNCTION(sc_cache_misses, TYPE_I32);
     DEFINE_RAISING_EXTERN_C_FUNCTION(sc_expand, arguments_type({TYPE_ValueRef, TYPE_List, TYPE_Scope}), TYPE_ValueRef, TYPE_List, TYPE_Scope);

          
@@ 2319,11 2326,14 @@ void init_globals(int argc, char *argv[]
     DEFINE_EXTERN_C_FUNCTION(sc_enter_solver_cli, _void);
     DEFINE_EXTERN_C_FUNCTION(sc_launch_args, arguments_type({TYPE_I32,native_ro_pointer_type(rawstring)}));
     DEFINE_EXTERN_C_FUNCTION(sc_set_typecast_handler, _void, TYPE_typecast_func);
+    DEFINE_EXTERN_C_FUNCTION(sc_prompt_set_autocomplete_handler, _void, TYPE_autocomplete_func);
 
     DEFINE_EXTERN_C_FUNCTION(sc_prompt, arguments_type({TYPE_Bool, TYPE_String}), TYPE_String, TYPE_String);
-    DEFINE_EXTERN_C_FUNCTION(sc_save_history, _void, TYPE_String);
-    DEFINE_EXTERN_C_FUNCTION(sc_load_history, _void, TYPE_String);
-    DEFINE_EXTERN_C_FUNCTION(sc_set_autocomplete_scope, _void, TYPE_Scope);
+    DEFINE_EXTERN_C_FUNCTION(sc_prompt_save_history, _void, TYPE_String);
+    DEFINE_EXTERN_C_FUNCTION(sc_prompt_load_history, _void, TYPE_String);
+    DEFINE_EXTERN_C_FUNCTION(sc_prompt_add_completion, _void, voidstar, rawstring);
+    DEFINE_EXTERN_C_FUNCTION(sc_prompt_add_completion_from_scope, _void, voidstar, rawstring, TYPE_Scope);
+
     DEFINE_EXTERN_C_FUNCTION(sc_default_styler, TYPE_String, TYPE_Symbol, TYPE_String);
     DEFINE_EXTERN_C_FUNCTION(sc_format_message, TYPE_String, TYPE_Anchor, TYPE_String);
     DEFINE_EXTERN_C_FUNCTION(sc_write, _void, TYPE_String);