1
0
mirror of https://github.com/janet-lang/janet synced 2026-04-04 05:51:27 +00:00

Compare commits

..

10 Commits

Author SHA1 Message Date
Calvin Rose
7d388f267a Update exceptions for os/execute with empty env test. 2026-03-02 19:24:12 -06:00
Calvin Rose
37a2677ecb Verbose testing for windows sanitizer build. 2026-03-02 19:17:10 -06:00
Calvin Rose
143ba6ba0f Add JanetOverlapped modification to filewatch. 2026-03-02 18:47:39 -06:00
Calvin Rose
0e8c3e3e0a Load connect lazily instead of in init. 2026-03-02 18:41:27 -06:00
Calvin Rose
4d13437c31 More tweaks for net.c 2026-03-02 18:31:15 -06:00
Calvin Rose
b134f5359d Correct missed overlappd conversions as reported by CI. 2026-03-02 18:26:28 -06:00
Calvin Rose
ce56342168 msvc does not have undefined behavior sanitizer. 2026-03-02 18:22:42 -06:00
Calvin Rose
ab86ef09ef Move declarations around for header fixes. 2026-03-02 18:21:37 -06:00
Calvin Rose
b8db108702 build_win tweaks. 2026-03-02 18:18:09 -06:00
Calvin Rose
479d846f7a WIP port of net/connect on windows to ConnectEx.
ConnectEx will let us restore non-blocking behavior on connect. Also
revisiting our IOCP implementation to see if we can do other
refactoring, such as removing code that tries to user OVERLAPPED
internals for no good reason.
2026-03-02 17:55:21 -06:00
8 changed files with 97 additions and 225 deletions

View File

@@ -3,8 +3,6 @@ All notable changes to this project will be documented in this file.
## Unreleased - ???
- Documentation fixes
- ev/thread-chan deadlock bug fixed
- Re-add removed support for non-blocking net/connect on windows.
## 1.41.2 - 2026-02-18
- Fix regressions in `put` for arrays and buffers.

View File

@@ -37,12 +37,6 @@ may require changes before being merged.
do this indentation, or approximate as close as possible. There is a janet formatter
in [spork](https://github.com/janet-lang/spork.git) that can be used to format code as well.
Bot pull requests will not be accepted, and anonymous submissions, including
new accounts, unknown emails, and first time contributors will be subjected
to greater scrutiny and code reivew. Automatically generated and filed bug
reports MAY be ok, if they are of consistent and good quality, such as
OSSFuzz or well constructed CI pipelines.
## C style
For changes to the VM and Core code, you will probably need to know C. Janet is programmed with
@@ -96,18 +90,3 @@ timely manner. In short, if you want extra functionality now, then build it.
* Include a good description of the problem that is being solved
* Include descriptions of potential solutions if you have some in mind.
## LLMs, Tool Usage, and Transparency
All usage of Large Language Models (LLMs), Neural Networks, "AI" tools, and
other tools such as software fuzzers or static analyzers must be disclosed.
This applies to pull requests, email patches, bug reports, and any other
meaningful contribution to Janet's source code. Please also refrain from using
generative AI for code that will be embedded in the Janet runtime, which include
all C source files as well as boot.janet. All code should be well
and completely understood by the human author, including test cases. Large and
obviously AI-driven changes will be rejected. Be mindful and transparent on the
copyright implications of any submitted code. We will use discretion when
accepting generated test cases for bug reproductions, one-line bug
fixes, or typo fixes. Often, these can be trivially rewritten by a human to
avoid the problem.

View File

@@ -443,36 +443,11 @@
(def ,binding ,ctor)
,(defer-impl :with [(or dtor :close) binding] body)))
# declare ahead of time
(var- macexvar nil)
(defmacro if-let
``Make multiple bindings, and if all are truthy,
evaluate the `tru` form. If any are false or nil, evaluate
the `fal` form. Bindings have the same syntax as the `let` macro.``
[bindings tru &opt fal]
(def len (length bindings))
(if (= 0 len) (error "expected at least 1 binding"))
(if (odd? len) (error "expected an even number of bindings"))
(def fal2 (if macexvar (macexvar fal) fal))
(defn aux [i]
(if (>= i len)
tru
(do
(def bl (in bindings i))
(def br (in bindings (+ 1 i)))
(if (symbol? bl)
~(if (def ,bl ,br) ,(aux (+ 2 i)) ,fal2)
~(if (def ,(def sym (gensym)) ,br)
(do (def ,bl ,sym) ,(aux (+ 2 i)))
,fal2)))))
(aux 0))
(defmacro when-with
``Similar to with, but if binding is false or nil, returns
nil without evaluating the body. Otherwise, the same as `with`.``
[[binding ctor dtor] & body]
~(as-macro ,if-let [,binding ,ctor]
~(if-let [,binding ,ctor]
,(defer-impl :when-with [(or dtor :close) binding] body)))
(defmacro if-with
@@ -480,7 +455,7 @@
the falsey path. Otherwise, evaluates the truthy path. In both cases,
`ctor` is bound to binding.``
[[binding ctor dtor] truthy &opt falsey]
~(as-macro ,if-let [,binding ,ctor]
~(if-let [,binding ,ctor]
,(defer-impl :if-with [(or dtor :close) binding] [truthy])
,falsey))
@@ -564,13 +539,13 @@
(case binding
:until ~(do (if ,verb (break) nil) ,rest)
:while ~(do (if ,verb nil (break)) ,rest)
:let ~(as-macro ,let ,verb (do ,rest))
:let ~(let ,verb (do ,rest))
:after ~(do ,rest ,verb nil)
:before ~(do ,verb ,rest nil)
:repeat (with-syms [iter]
~(do (var ,iter ,verb) (while (,> ,iter 0) ,rest (as-macro ,-- ,iter))))
:when ~(as-macro ,when ,verb ,rest)
:unless ~(as-macro ,unless ,verb ,rest)
~(do (var ,iter ,verb) (while (> ,iter 0) ,rest (-- ,iter))))
:when ~(when ,verb ,rest)
:unless ~(unless ,verb ,rest)
(error (string "unexpected loop modifier " binding))))))
# 3 term expression
@@ -612,7 +587,7 @@
"Evaluate body n times. If n is negative, body will be evaluated 0 times. Evaluates to nil."
[n & body]
(with-syms [iter]
~(do (var ,iter ,n) (while (,> ,iter 0) ,;body (as-macro ,-- ,iter)))))
~(do (var ,iter ,n) (while (> ,iter 0) ,;body (-- ,iter)))))
(defmacro forever
"Evaluate body forever in a loop, or until a break statement."
@@ -708,7 +683,7 @@
[head & body]
(def $accum (gensym))
(check-empty-body body)
~(do (def ,$accum @[]) (as-macro ,loop ,head (,array/push ,$accum (do ,;body))) ,$accum))
~(do (def ,$accum @[]) (loop ,head (,array/push ,$accum (do ,;body))) ,$accum))
(defmacro catseq
``Similar to `loop`, but concatenates each element from the loop body into an array and returns that.
@@ -716,21 +691,21 @@
[head & body]
(def $accum (gensym))
(check-empty-body body)
~(do (def ,$accum @[]) (as-macro ,loop ,head (,array/concat ,$accum (do ,;body))) ,$accum))
~(do (def ,$accum @[]) (loop ,head (,array/concat ,$accum (do ,;body))) ,$accum))
(defmacro tabseq
``Similar to `loop`, but accumulates key value pairs into a table.
See `loop` for details.``
[head key-body & value-body]
(def $accum (gensym))
~(do (def ,$accum @{}) (as-macro ,loop ,head (,put ,$accum ,key-body (do ,;value-body))) ,$accum))
~(do (def ,$accum @{}) (loop ,head (,put ,$accum ,key-body (do ,;value-body))) ,$accum))
(defmacro generate
``Create a generator expression using the `loop` syntax. Returns a fiber
that yields all values inside the loop in order. See `loop` for details.``
[head & body]
(check-empty-body body)
~(,fiber/new (fn :generate [] (as-macro ,loop ,head (,yield (do ,;body)))) :yi))
~(,fiber/new (fn :generate [] (loop ,head (yield (do ,;body)))) :yi))
(defmacro coro
"A wrapper for making fibers that may yield multiple values (coroutine). Same as `(fiber/new (fn [] ;body) :yi)`."
@@ -779,10 +754,35 @@
(each x xs (*= accum x))
accum)
# declare ahead of time
(var- macexvar nil)
(defmacro if-let
``Make multiple bindings, and if all are truthy,
evaluate the `tru` form. If any are false or nil, evaluate
the `fal` form. Bindings have the same syntax as the `let` macro.``
[bindings tru &opt fal]
(def len (length bindings))
(if (= 0 len) (error "expected at least 1 binding"))
(if (odd? len) (error "expected an even number of bindings"))
(def fal2 (if macexvar (macexvar fal) fal))
(defn aux [i]
(if (>= i len)
tru
(do
(def bl (in bindings i))
(def br (in bindings (+ 1 i)))
(if (symbol? bl)
~(if (def ,bl ,br) ,(aux (+ 2 i)) ,fal2)
~(if (def ,(def sym (gensym)) ,br)
(do (def ,bl ,sym) ,(aux (+ 2 i)))
,fal2)))))
(aux 0))
(defmacro when-let
"Same as `(if-let bindings (do ;body))`."
[bindings & body]
~(as-macro ,if-let ,bindings (do ,;body)))
~(if-let ,bindings (do ,;body)))
(defn comp
`Takes multiple functions and returns a function that is the composition
@@ -1432,7 +1432,7 @@
(tuple n @[])))
(def sym (gensym))
(def parts (array/concat @[h sym] t))
~(as-macro ,let [,sym ,last] (if ,sym ,(keep-syntax! n parts))))
~(let [,sym ,last] (if ,sym ,(keep-syntax! n parts))))
(reduce fop x forms))
(defmacro -?>>
@@ -1448,7 +1448,7 @@
(tuple n @[])))
(def sym (gensym))
(def parts (array/concat @[h] t @[sym]))
~(as-macro ,let [,sym ,last] (if ,sym ,(keep-syntax! n parts))))
~(let [,sym ,last] (if ,sym ,(keep-syntax! n parts))))
(reduce fop x forms))
(defn- walk-ind [f form]
@@ -2411,8 +2411,8 @@
(dictionary? m) (merge-into metadata m)
(error (string "invalid metadata " m))))
(with-syms [entry old-entry f]
~(as-macro ,let [,old-entry (,dyn ',name)]
(def ,entry (as-macro ,or ,old-entry @{:ref @[nil]}))
~(let [,old-entry (,dyn ',name)]
(def ,entry (or ,old-entry @{:ref @[nil]}))
(,setdyn ',name ,entry)
(def ,f ,fbody)
(,put-in ,entry [:ref 0] ,f)
@@ -3953,7 +3953,7 @@
``
[sec & body]
(with-syms [f]
~(as-macro ,let [,f (as-macro ,coro ,;body)]
~(let [,f (coro ,;body)]
(,ev/deadline ,sec nil ,f)
(,resume ,f))))
@@ -4085,15 +4085,15 @@
(defn make-ptr []
(assertf (ffi/lookup (if lazy (llib) lib) raw-symbol) "failed to find ffi symbol %v" raw-symbol))
(if lazy
~(as-macro ,defn ,alias ,;meta [,;formal-args]
~(defn ,alias ,;meta [,;formal-args]
(,ffi/call (,(delay (make-ptr))) (,(delay (make-sig))) ,;formal-args))
~(as-macro ,defn ,alias ,;meta [,;formal-args]
~(defn ,alias ,;meta [,;formal-args]
(,ffi/call ,(make-ptr) ,(make-sig) ,;formal-args))))
(defmacro ffi/defbind :flycheck
"Generate bindings for native functions in a convenient manner."
[name ret-type & body]
~(as-macro ,ffi/defbind-alias ,name ,name ,ret-type ,;body)))
~(ffi/defbind-alias ,name ,name ,ret-type ,;body)))
###
###

View File

@@ -1110,7 +1110,6 @@ JANET_CORE_FN(cfun_disasm,
if (!janet_cstrcmp(kw, "structarg")) return janet_disasm_structarg(f->def);
if (!janet_cstrcmp(kw, "namedargs")) return janet_disasm_namedargs(f->def);
if (!janet_cstrcmp(kw, "slotcount")) return janet_disasm_slotcount(f->def);
if (!janet_cstrcmp(kw, "symbolmap")) return janet_disasm_symbolslots(f->def);
if (!janet_cstrcmp(kw, "constants")) return janet_disasm_constants(f->def);
if (!janet_cstrcmp(kw, "sourcemap")) return janet_disasm_sourcemap(f->def);
if (!janet_cstrcmp(kw, "environments")) return janet_disasm_environments(f->def);

View File

@@ -1172,7 +1172,7 @@ JanetChannel *janet_channel_make(uint32_t limit) {
JanetChannel *janet_channel_make_threaded(uint32_t limit) {
janet_assert(limit <= INT32_MAX, "bad limit");
JanetChannel *channel = janet_abstract_threaded(&janet_channel_type, sizeof(JanetChannel));
janet_chan_init(channel, (int32_t) limit, 1);
janet_chan_init(channel, (int32_t) limit, 0);
return channel;
}

View File

@@ -72,7 +72,7 @@ static int count_dig10(int32_t x) {
}
}
static int32_t integer_to_string_b(JanetBuffer *buffer, int32_t x) {
static void integer_to_string_b(JanetBuffer *buffer, int32_t x) {
janet_buffer_extra(buffer, BUFSIZE);
uint8_t *buf = buffer->data + buffer->count;
int32_t neg = 0;
@@ -80,7 +80,7 @@ static int32_t integer_to_string_b(JanetBuffer *buffer, int32_t x) {
if (x == 0) {
buf[0] = '0';
buffer->count++;
return 1;
return;
}
if (x > 0) {
x = -x;
@@ -96,7 +96,6 @@ static int32_t integer_to_string_b(JanetBuffer *buffer, int32_t x) {
x /= 10;
}
buffer->count += len + neg;
return len + neg;
}
#define HEX(i) (((uint8_t *) janet_base64)[(i)])
@@ -135,55 +134,43 @@ static void string_description_b(JanetBuffer *buffer, const char *title, void *p
#undef POINTSIZE
}
static int janet_escape_string_impl(JanetBuffer *buffer, const uint8_t *str, int32_t len) {
static void janet_escape_string_impl(JanetBuffer *buffer, const uint8_t *str, int32_t len) {
janet_buffer_push_u8(buffer, '"');
int align = 1;
for (int32_t i = 0; i < len; ++i) {
uint8_t c = str[i];
switch (c) {
case '"':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\\"", 2);
align += 2;
break;
case '\n':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\n", 2);
align += 2;
break;
case '\r':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\r", 2);
align += 2;
break;
case '\0':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\0", 2);
align += 2;
break;
case '\f':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\f", 2);
align += 2;
break;
case '\v':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\v", 2);
align += 2;
break;
case '\a':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\a", 2);
align += 2;
break;
case '\b':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\b", 2);
align += 2;
break;
case 27:
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\e", 2);
align += 2;
break;
case '\\':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\\\", 2);
align += 2;
break;
case '\t':
janet_buffer_push_bytes(buffer, (const uint8_t *)"\\t", 2);
align += 2;
break;
default:
if (c < 32 || c > 126) {
@@ -193,16 +180,13 @@ static int janet_escape_string_impl(JanetBuffer *buffer, const uint8_t *str, int
buf[2] = janet_base64[(c >> 4) & 0xF];
buf[3] = janet_base64[c & 0xF];
janet_buffer_push_bytes(buffer, buf, 4);
align += 4;
} else {
janet_buffer_push_u8(buffer, c);
align++;
}
break;
}
}
janet_buffer_push_u8(buffer, '"');
return align + 1;
}
static void janet_escape_string_b(JanetBuffer *buffer, const uint8_t *str) {
@@ -374,7 +358,7 @@ const uint8_t *janet_to_string(Janet x) {
struct pretty {
JanetBuffer *buffer;
int depth;
int align;
int indent;
int flags;
int32_t bufstartlen;
int32_t *keysort_buffer;
@@ -466,15 +450,14 @@ static int print_jdn_one(struct pretty *S, Janet x, int depth) {
return 0;
}
static void print_newline(struct pretty *S, int align) {
static void print_newline(struct pretty *S, int just_a_space) {
int i;
S->align = align;
if (S->flags & JANET_PRETTY_ONELINE) {
if (just_a_space || (S->flags & JANET_PRETTY_ONELINE)) {
janet_buffer_push_u8(S->buffer, ' ');
return;
}
janet_buffer_push_u8(S->buffer, '\n');
for (i = 0; i < S->align; i++) {
for (i = 0; i < S->indent; i++) {
janet_buffer_push_u8(S->buffer, ' ');
}
}
@@ -501,12 +484,14 @@ static const char *janet_pretty_colors[] = {
"\x1B[36m"
};
#define JANET_PRETTY_DICT_ONELINE 4
#define JANET_PRETTY_IND_ONELINE 10
#define JANET_PRETTY_DICT_LIMIT 30
#define JANET_PRETTY_DICT_KEYSORT_LIMIT 2000
#define JANET_PRETTY_ARRAY_LIMIT 160
/* Helper for pretty printing */
static void janet_pretty_one(struct pretty *S, Janet x) {
static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
/* Add to seen */
switch (janet_type(x)) {
case JANET_NIL:
@@ -521,7 +506,7 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
janet_buffer_push_cstring(S->buffer, janet_cycle_color);
}
janet_buffer_push_cstring(S->buffer, "<cycle ");
S->align += 8 + integer_to_string_b(S->buffer, janet_unwrap_integer(seenid));
integer_to_string_b(S->buffer, janet_unwrap_integer(seenid));
janet_buffer_push_u8(S->buffer, '>');
if (S->flags & JANET_PRETTY_COLOR) {
janet_buffer_push_cstring(S->buffer, "\x1B[0m");
@@ -543,11 +528,9 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
if (janet_checktype(x, JANET_BUFFER) && janet_unwrap_buffer(x) == S->buffer) {
janet_buffer_ensure(S->buffer, S->buffer->count + S->bufstartlen * 4 + 3, 1);
janet_buffer_push_u8(S->buffer, '@');
S->align += 1 + janet_escape_string_impl(S->buffer, S->buffer->data, S->bufstartlen);
janet_escape_string_impl(S->buffer, S->buffer->data, S->bufstartlen);
} else {
S->align -= S->buffer->count;
janet_description_b(S->buffer, x);
S->align += S->buffer->count;
}
if (color && (S->flags & JANET_PRETTY_COLOR)) {
janet_buffer_push_cstring(S->buffer, "\x1B[0m");
@@ -564,34 +547,35 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
const char *startstr = isarray ? "@[" : hasbrackets ? "[" : "(";
const char endchar = isarray ? ']' : hasbrackets ? ']' : ')';
janet_buffer_push_cstring(S->buffer, startstr);
const int align = S->align += strlen(startstr);
S->depth--;
S->indent += 2;
if (S->depth == 0) {
janet_buffer_push_cstring(S->buffer, "...");
S->align += 3;
} else {
if (!isarray && !(S->flags & JANET_PRETTY_ONELINE) && len >= JANET_PRETTY_IND_ONELINE)
janet_buffer_push_u8(S->buffer, ' ');
if (is_dict_value && len >= JANET_PRETTY_IND_ONELINE) print_newline(S, 0);
if (len > JANET_PRETTY_ARRAY_LIMIT && !(S->flags & JANET_PRETTY_NOTRUNC)) {
for (i = 0; i < 3; i++) {
if (i) print_newline(S, align);
janet_pretty_one(S, arr[i]);
if (i) print_newline(S, 0);
janet_pretty_one(S, arr[i], 0);
}
print_newline(S, align);
print_newline(S, 0);
janet_buffer_push_cstring(S->buffer, "...");
S->align += 3;
for (i = len - 3; i < len; i++) {
print_newline(S, align);
janet_pretty_one(S, arr[i]);
for (i = 0; i < 3; i++) {
print_newline(S, 0);
janet_pretty_one(S, arr[len - 3 + i], 0);
}
} else {
for (i = 0; i < len; i++) {
if (i) print_newline(S, align);
janet_pretty_one(S, arr[i]);
if (i) print_newline(S, len < JANET_PRETTY_IND_ONELINE);
janet_pretty_one(S, arr[i], 0);
}
}
}
S->indent -= 2;
S->depth++;
janet_buffer_push_u8(S->buffer, endchar);
S->align++;
break;
}
case JANET_STRUCT:
@@ -602,7 +586,6 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
if (istable) {
JanetTable *t = janet_unwrap_table(x);
JanetTable *proto = t->proto;
S->align++;
janet_buffer_push_cstring(S->buffer, "@");
if (NULL != proto) {
Janet name = janet_table_get(proto, janet_ckeywordv("_name"));
@@ -613,7 +596,6 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
janet_buffer_push_cstring(S->buffer, janet_class_color);
}
janet_buffer_push_bytes(S->buffer, n, len);
S->align += len;
if (S->flags & JANET_PRETTY_COLOR) {
janet_buffer_push_cstring(S->buffer, "\x1B[0m");
}
@@ -631,24 +613,25 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
janet_buffer_push_cstring(S->buffer, janet_class_color);
}
janet_buffer_push_bytes(S->buffer, n, len);
S->align += len;
if (S->flags & JANET_PRETTY_COLOR) {
janet_buffer_push_cstring(S->buffer, "\x1B[0m");
}
}
}
}
janet_buffer_push_u8(S->buffer, '{');
const int align = ++S->align;
janet_buffer_push_cstring(S->buffer, "{");
S->depth--;
S->indent += 2;
if (S->depth == 0) {
janet_buffer_push_cstring(S->buffer, "...");
S->align += 3;
} else {
int32_t len = 0, cap = 0;
const JanetKV *kvs = NULL;
janet_dictionary_view(x, &kvs, &len, &cap);
if (!istable && !(S->flags & JANET_PRETTY_ONELINE) && len >= JANET_PRETTY_DICT_ONELINE)
janet_buffer_push_u8(S->buffer, ' ');
if (is_dict_value && len >= JANET_PRETTY_DICT_ONELINE) print_newline(S, 0);
int32_t ks_start = S->keysort_start;
int truncated = 0;
@@ -661,17 +644,15 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
int32_t j = 0;
for (int32_t i = 0; i < len; i++) {
while (janet_checktype(kvs[j].key, JANET_NIL)) j++;
if (i) print_newline(S, align);
janet_pretty_one(S, kvs[j].key);
if (i) print_newline(S, len < JANET_PRETTY_DICT_ONELINE);
janet_pretty_one(S, kvs[j].key, 0);
janet_buffer_push_u8(S->buffer, ' ');
S->align++;
janet_pretty_one(S, kvs[j].value);
janet_pretty_one(S, kvs[j].value, 1);
j++;
}
if (truncated) {
print_newline(S, align);
print_newline(S, 0);
janet_buffer_push_cstring(S->buffer, "...");
S->align += 3;
}
} else {
/* Sorted keys dictionaries */
@@ -704,26 +685,24 @@ static void janet_pretty_one(struct pretty *S, Janet x) {
}
for (int32_t i = 0; i < len; i++) {
if (i) print_newline(S, align);
if (i) print_newline(S, len < JANET_PRETTY_DICT_ONELINE);
int32_t j = S->keysort_buffer[i + ks_start];
janet_pretty_one(S, kvs[j].key);
janet_pretty_one(S, kvs[j].key, 0);
janet_buffer_push_u8(S->buffer, ' ');
S->align++;
janet_pretty_one(S, kvs[j].value);
janet_pretty_one(S, kvs[j].value, 1);
}
if (truncated) {
print_newline(S, align);
print_newline(S, 0);
janet_buffer_push_cstring(S->buffer, "...");
S->align += 3;
}
}
S->keysort_start = ks_start;
}
S->indent -= 2;
S->depth++;
janet_buffer_push_u8(S->buffer, '}');
S->align++;
break;
}
}
@@ -739,14 +718,14 @@ static JanetBuffer *janet_pretty_(JanetBuffer *buffer, int depth, int flags, Jan
}
S.buffer = buffer;
S.depth = depth;
S.align = 0;
S.indent = 0;
S.flags = flags;
S.bufstartlen = startlen;
S.keysort_capacity = 0;
S.keysort_buffer = NULL;
S.keysort_start = 0;
janet_table_init(&S.seen, 10);
janet_pretty_one(&S, x);
janet_pretty_one(&S, x, 0);
janet_table_deinit(&S.seen);
return S.buffer;
}
@@ -764,7 +743,7 @@ static JanetBuffer *janet_jdn_(JanetBuffer *buffer, int depth, Janet x, int32_t
}
S.buffer = buffer;
S.depth = depth;
S.align = 0;
S.indent = 0;
S.flags = 0;
S.bufstartlen = startlen;
S.keysort_capacity = 0;

View File

@@ -26,7 +26,6 @@
#include <janet.h>
#include <errno.h>
#include <assert.h>
#ifdef _WIN32
#include <windows.h>
@@ -363,50 +362,33 @@ static void clear(void) {
}
}
static int getplen(void) {
int _plen = gbl_plen;
/* Ensure at least 16 characters of data entry; */
while (_plen && (_plen + 16 > gbl_cols)) {
_plen--;
}
return _plen;
}
static void refresh(void) {
char seq[64];
JanetBuffer b;
/* If prompt is too long, truncate */
int _plen = getplen();
/* Keep cursor position on screen */
char *_buf = gbl_buf;
int _len = gbl_len;
int _pos = gbl_pos;
while ((_plen + _pos) >= gbl_cols) {
while ((gbl_plen + _pos) >= gbl_cols) {
_buf++;
_len--;
_pos--;
}
while ((_plen + _len) > gbl_cols) {
while ((gbl_plen + _len) > gbl_cols) {
_len--;
}
janet_buffer_init(&b, 0);
/* Cursor to left edge, gbl_prompt and buffer */
janet_buffer_push_u8(&b, '\r');
janet_buffer_push_bytes(&b, (const uint8_t *) gbl_prompt, _plen);
if (_len > 0) {
janet_buffer_push_bytes(&b, (uint8_t *) _buf, _len);
}
janet_buffer_push_cstring(&b, gbl_prompt);
janet_buffer_push_bytes(&b, (uint8_t *) _buf, _len);
/* Erase to right */
janet_buffer_push_cstring(&b, "\x1b[0K\r");
/* Move cursor to original position. */
if (_pos + _plen) {
snprintf(seq, 64, "\x1b[%dC", (int)(_pos + _plen));
if (_pos + gbl_plen) {
snprintf(seq, 64, "\x1b[%dC", (int)(_pos + gbl_plen));
janet_buffer_push_cstring(&b, seq);
}
if (write_console((char *) b.data, b.count) == -1) {
@@ -432,8 +414,7 @@ static int insert(char c, int draw) {
gbl_buf[gbl_pos++] = c;
gbl_buf[++gbl_len] = '\0';
if (draw) {
int _plen = getplen();
if (_plen + gbl_len < gbl_cols) {
if (gbl_plen + gbl_len < gbl_cols) {
/* Avoid a full update of the line in the
* trivial case. */
if (write_console(&c, 1) == -1) return -1;
@@ -944,12 +925,11 @@ static int line() {
gbl_len = 0;
gbl_pos = 0;
while (gbl_prompt[gbl_plen]) gbl_plen++;
int _plen = getplen();
gbl_buf[0] = '\0';
addhistory();
if (write_console((char *) gbl_prompt, _plen) == -1) return -1;
if (write_console((char *) gbl_prompt, gbl_plen) == -1) return -1;
for (;;) {
char c;
char seq[5];

View File

@@ -61,68 +61,5 @@
(check-jdn "a string")
(check-jdn @"a buffer")
# Test multiline pretty specifiers
(let [tup [:keyword "string" @"buffer"]
tab @{true (table/setproto @{:bar tup
:baz 42}
@{:_name "Foo"})}]
(set (tab tup) tab)
(assert (= (string/format "%m" {tup @[tup tab]
'symbol tup})
`
{symbol (:keyword
"string"
@"buffer")
(:keyword
"string"
@"buffer") @[(:keyword
"string"
@"buffer")
@{true @Foo{:bar (:keyword
"string"
@"buffer")
:baz 42}
(:keyword
"string"
@"buffer") <cycle 2>}]}`))
(assert (= (string/format "%p" {(freeze (zipcoll (range 42)
(range -42 0))) tab})
`
{{0 -42
1 -41
2 -40
3 -39
4 -38
5 -37
6 -36
7 -35
8 -34
9 -33
10 -32
11 -31
12 -30
13 -29
14 -28
15 -27
16 -26
17 -25
18 -24
19 -23
20 -22
21 -21
22 -20
23 -19
24 -18
25 -17
26 -16
27 -15
28 -14
29 -13
...} @{true @Foo{:bar (:keyword
"string"
@"buffer")
:baz 42}
(:keyword
"string"
@"buffer") <cycle 1>}}`)))
(end-suite)