Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
2 : : // SPDX-FileCopyrightText: 2018 Philip Chimento <philip.chimento@gmail.com>
3 : : // SPDX-FileContributor: Philip Chimento <philip.chimento@gmail.com>
4 : :
5 : : #include <config.h> // for HAVE_READLINE_READLINE_H, HAVE_UNISTD_H
6 : :
7 : : #include <stdint.h>
8 : : #include <stdio.h> // for feof, fflush, fgets, stdin, stdout
9 : :
10 : : #ifdef HAVE_READLINE_READLINE_H
11 : : # include <readline/history.h>
12 : : # include <readline/readline.h>
13 : : #endif
14 : :
15 : : #include <glib.h>
16 : :
17 : : #include <js/CallArgs.h>
18 : : #include <js/PropertyAndElement.h>
19 : : #include <js/PropertySpec.h>
20 : : #include <js/Realm.h>
21 : : #include <js/RootingAPI.h>
22 : : #include <js/String.h>
23 : : #include <js/TypeDecls.h>
24 : : #include <js/Utility.h> // for UniqueChars
25 : : #include <js/Value.h>
26 : : #include <jsapi.h> // for JS_WrapObject
27 : :
28 : : #include "gjs/atoms.h"
29 : : #include "gjs/auto.h"
30 : : #include "gjs/context-private.h"
31 : : #include "gjs/context.h"
32 : : #include "gjs/global.h"
33 : : #include "gjs/jsapi-util-args.h"
34 : : #include "gjs/jsapi-util.h"
35 : : #include "gjs/macros.h"
36 : : #include "gjs/module.h"
37 : :
38 : : #include "util/console.h"
39 : :
40 : : GJS_JSAPI_RETURN_CONVENTION
41 : 9 : static bool quit(JSContext* cx, unsigned argc, JS::Value* vp) {
42 : 9 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
43 : :
44 : : int32_t exitcode;
45 [ - + ]: 9 : if (!gjs_parse_call_args(cx, "quit", args, "i", "exitcode", &exitcode))
46 : 0 : return false;
47 : :
48 : 9 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
49 : 9 : gjs->exit(exitcode);
50 : 9 : return false; // without gjs_throw() == "throw uncatchable exception"
51 : : }
52 : :
53 : : GJS_JSAPI_RETURN_CONVENTION
54 : 270 : static bool do_readline(JSContext* cx, unsigned argc, JS::Value* vp) {
55 : 270 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
56 : :
57 : 270 : JS::UniqueChars prompt;
58 [ - + ]: 270 : if (!gjs_parse_call_args(cx, "readline", args, "|s", "prompt", &prompt))
59 : 0 : return false;
60 : :
61 : 270 : Gjs::AutoChar line;
62 : : do {
63 [ - + ]: 270 : const char* real_prompt = prompt ? prompt.get() : "db> ";
64 : : #ifdef HAVE_READLINE_READLINE_H
65 [ - + ]: 270 : if (gjs_console_is_tty(stdin_fd)) {
66 : 0 : line = readline(real_prompt);
67 : : } else {
68 : : #else
69 : : {
70 : : #endif // HAVE_READLINE_READLINE_H
71 : : char buf[256];
72 : 270 : g_print("%s", real_prompt);
73 : 270 : fflush(stdout);
74 [ + + ]: 270 : if (!fgets(buf, sizeof buf, stdin))
75 : 4 : buf[0] = '\0';
76 : 540 : line.reset(g_strdup(g_strchomp(buf)));
77 : :
78 [ + - ]: 270 : if (!gjs_console_is_tty(stdin_fd)) {
79 [ + + ]: 270 : if (feof(stdin)) {
80 : 4 : g_print("[quit due to end of input]\n");
81 : 4 : line.reset(g_strdup("quit"));
82 : : } else {
83 : 266 : g_print("%s\n", line.get());
84 : : }
85 : : }
86 : : }
87 : :
88 : : /* EOF, return null */
89 [ - + ]: 270 : if (!line) {
90 : 0 : args.rval().setNull();
91 : 0 : return true;
92 : : }
93 [ + - - + : 270 : } while (line && line.get()[0] == '\0');
- + ]
94 : :
95 : : /* Add line to history and convert it to a JSString so that we can pass it
96 : : * back as the return value */
97 : : #ifdef HAVE_READLINE_READLINE_H
98 : 270 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
99 : 270 : add_history(line);
100 : 270 : gjs_console_write_repl_history(gjs->repl_history_path());
101 : : #endif
102 : 270 : args.rval().setString(JS_NewStringCopyZ(cx, line));
103 : 270 : return true;
104 : 270 : }
105 : :
106 : 138 : static bool get_source_map_registry(JSContext* cx, unsigned argc,
107 : : JS::Value* vp) {
108 : 138 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
109 : 138 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
110 : :
111 : 138 : JS::RootedObject registry{cx, gjs_get_source_map_registry(gjs->global())};
112 [ - + ]: 138 : if (!JS_WrapObject(cx, ®istry)) {
113 : 0 : gjs_log_exception(cx);
114 : 0 : return false;
115 : : }
116 : 138 : args.rval().setObject(*registry);
117 : 138 : return true;
118 : 138 : }
119 : :
120 : : // clang-format off
121 : : static JSFunctionSpec debugger_funcs[] = {
122 : : JS_FN("quit", quit, 1, GJS_MODULE_PROP_FLAGS),
123 : : JS_FN("readline", do_readline, 1, GJS_MODULE_PROP_FLAGS),
124 : : JS_FN("getSourceMapRegistry", get_source_map_registry, 0, GJS_MODULE_PROP_FLAGS),
125 : : JS_FS_END
126 : : };
127 : : // clang-format on
128 : :
129 : 24 : void gjs_context_setup_debugger_console(GjsContext* self) {
130 : 24 : auto* gjs = GjsContextPrivate::from_object(self);
131 : 24 : JSContext* cx = gjs->context();
132 : :
133 : : JS::RootedObject debugger_global(
134 : 24 : cx, gjs_create_global_object(cx, GjsGlobalType::DEBUGGER));
135 : :
136 : : // Enter realm of the debugger and initialize it with the debuggee
137 : 24 : JSAutoRealm ar(cx, debugger_global);
138 : 24 : JS::RootedObject debuggee{cx, gjs->global()};
139 [ - + ]: 24 : if (!JS_WrapObject(cx, &debuggee)) {
140 : 0 : gjs_log_exception(cx);
141 : 0 : return;
142 : : }
143 : :
144 : 24 : JS::RootedValue v_debuggee(cx, JS::ObjectValue(*debuggee));
145 : 24 : if (!JS_SetPropertyById(cx, debugger_global, gjs->atoms().debuggee(),
146 : 24 : v_debuggee) ||
147 [ + - + - ]: 48 : !JS_DefineFunctions(cx, debugger_global, debugger_funcs) ||
148 [ - + - + ]: 48 : !gjs_define_global_properties(cx, debugger_global,
149 : : GjsGlobalType::DEBUGGER, "GJS debugger",
150 : : "debugger"))
151 : 0 : gjs_log_exception(cx);
152 [ + - + - : 24 : }
+ - ]
|