diff --git a/TeXmacs/plugins/goldfish/goldfish/liii/hash-table.scm b/TeXmacs/plugins/goldfish/goldfish/liii/hash-table.scm index 8607f3accd..5fed0dde83 100644 --- a/TeXmacs/plugins/goldfish/goldfish/liii/hash-table.scm +++ b/TeXmacs/plugins/goldfish/goldfish/liii/hash-table.scm @@ -27,7 +27,7 @@ hash-table-size hash-table-keys hash-table-values hash-table-entries hash-table-find hash-table-count hash-table-fold hash-table-for-each hash-table-map->list - hash-table->alist + hash-table->alist hash-table-copy ) (begin ) ; end of begin diff --git a/TeXmacs/plugins/goldfish/goldfish/liii/hashlib.scm b/TeXmacs/plugins/goldfish/goldfish/liii/hashlib.scm index f9106908c8..bf8021265b 100644 --- a/TeXmacs/plugins/goldfish/goldfish/liii/hashlib.scm +++ b/TeXmacs/plugins/goldfish/goldfish/liii/hashlib.scm @@ -14,12 +14,17 @@ ; under the License. ; (define-library (liii hashlib) - (export md5 sha1 sha256) + (export md5 sha1 sha256 + md5-by-file sha1-by-file sha256-by-file) (begin (define (md5 str) (g_md5 str)) (define (sha1 str) (g_sha1 str)) (define (sha256 str) (g_sha256 str)) + (define (md5-by-file path) (g_md5-by-file path)) + (define (sha1-by-file path) (g_sha1-by-file path)) + (define (sha256-by-file path) (g_sha256-by-file path)) + ) ; end of begin ) ; end of define-library diff --git a/TeXmacs/plugins/goldfish/goldfish/liii/http.scm b/TeXmacs/plugins/goldfish/goldfish/liii/http.scm index 0207721b16..d599b8df7f 100644 --- a/TeXmacs/plugins/goldfish/goldfish/liii/http.scm +++ b/TeXmacs/plugins/goldfish/goldfish/liii/http.scm @@ -7,7 +7,8 @@ (import (liii hash-table) (liii alist)) (export http-head http-get http-post http-ok? - http-stream-get http-stream-post) + http-stream-get http-stream-post + http-async-get http-async-post http-async-head http-poll http-wait-all) (begin (define (http-ok? r) @@ -65,6 +66,43 @@ (g_http-stream-post url params data '(("Content-Type" . "text/plain")) proxy userdata callback)) (else (g_http-stream-post url params data headers proxy userdata callback)))) +;; Async HTTP API wrapper functions + +(define* (http-async-get url callback (params '()) (headers '()) (proxy '())) + (when (not (alist? params)) + (type-error params "is not a association list")) + (when (not (alist? proxy)) + (type-error proxy "is not a association list")) + (when (not (procedure? callback)) + (type-error callback "is not a procedure")) + (g_http-async-get url params headers proxy callback)) + +(define* (http-async-post url callback (params '()) (data "") (headers '()) (proxy '())) + (when (not (alist? params)) + (type-error params "is not a association list")) + (when (not (alist? proxy)) + (type-error proxy "is not a association list")) + (when (not (procedure? callback)) + (type-error callback "is not a procedure")) + (cond ((and (string? data) (> (string-length data) 0) (null? headers)) + (g_http-async-post url params data '(("Content-Type" . "text/plain")) proxy callback)) + (else (g_http-async-post url params data headers proxy callback)))) + +(define* (http-async-head url callback (params '()) (headers '()) (proxy '())) + (when (not (alist? params)) + (type-error params "is not a association list")) + (when (not (alist? proxy)) + (type-error proxy "is not a association list")) + (when (not (procedure? callback)) + (type-error callback "is not a procedure")) + (g_http-async-head url params headers proxy callback)) + +(define (http-poll) + (g_http-poll)) + +(define* (http-wait-all (timeout -1)) + (g_http-wait-all timeout)) + ) ; end of begin ) ; end of define-library diff --git a/TeXmacs/plugins/goldfish/goldfish/scheme/time.scm b/TeXmacs/plugins/goldfish/goldfish/scheme/time.scm index 3630dfb9c3..bbdebf90e2 100644 --- a/TeXmacs/plugins/goldfish/goldfish/scheme/time.scm +++ b/TeXmacs/plugins/goldfish/goldfish/scheme/time.scm @@ -15,15 +15,26 @@ ; (define-library (scheme time) - (export current-second current-jiffy jiffies-per-second) + (import (only (scheme base) let-values s7-round)) + (export current-second current-jiffy jiffies-per-second + get-time-of-day monotonic-nanosecond + system-clock-resolution steady-clock-resolution) (begin (define (jiffies-per-second) 1000000) - (define (current-second) (g_current-second)) + (define get-time-of-day g_get-time-of-day) + (define monotonic-nanosecond g_monotonic-nanosecond) + (define system-clock-resolution g_system-clock-resolution) + (define steady-clock-resolution g_steady-clock-resolution) + + (define (current-second) + (let-values (((sec usec) (get-time-of-day))) + (+ sec (exact->inexact (/ usec 1000000))))) (define (current-jiffy) - (round (* (current-second) (jiffies-per-second)))) + ;; NOTE: use the s7-round to ensure that a natural number is returned. + (s7-round (* (current-second) (jiffies-per-second)))) ) ; end of begin ) ; end of define-library diff --git a/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-125.scm b/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-125.scm index 690540b7de..30b12ed017 100644 --- a/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-125.scm +++ b/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-125.scm @@ -22,7 +22,7 @@ hash-table-update! hash-table-update!/default hash-table-pop! hash-table-clear! hash-table-size hash-table-keys hash-table-values hash-table-entries hash-table-find hash-table-count hash-table-fold hash-table-for-each hash-table-map->list - hash-table->alist) + hash-table->alist hash-table-copy) (begin (define (assert-hash-table-type ht f) @@ -148,4 +148,14 @@ (define hash-table->alist (typed-lambda ((ht hash-table?)) - (append-map (lambda (x) (list (car x) (cdr x))) (map values ht)))))) + (append-map (lambda (x) (list (car x) (cdr x))) (map values ht)))) + + (define hash-table-copy + (typed-lambda ((ht hash-table?) . rest) + (let ((new-ht (make-hash-table)) + (mutable? (if (null? rest) #t (car rest)))) + (hash-table-for-each + (lambda (k v) + (hash-table-set! new-ht k v)) + ht) + new-ht))))) diff --git a/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-165.scm b/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-165.scm new file mode 100644 index 0000000000..f84f7e0b5e --- /dev/null +++ b/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-165.scm @@ -0,0 +1,378 @@ +; +; Copyright (C) 2026 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +;; Based on Marc Nieper-Wißkirchen MIT implementation + +;; Copyright (C) Marc Nieper-Wißkirchen (2019). All Rights Reserved. + +;; Permission is hereby granted, free of charge, to any person +;; obtaining a copy of this software and associated documentation +;; files (the "Software"), to deal in the Software without +;; restriction, including without limitation the rights to use, copy, +;; modify, merge, publish, distribute, sublicense, and/or sell copies +;; of the Software, and to permit persons to whom the Software is +;; furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice (including +;; the next paragraph) shall be included in all copies or substantial +;; portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. + +(define-library (srfi srfi-165) + (import (srfi srfi-1) + (srfi srfi-128) + (srfi srfi-125)) + (export + make-computation-environment-variable + make-computation-environment + computation-environment-ref + computation-environment-update + computation-environment-update! + computation-environment-copy + + make-computation + computation-run + computation-ask + computation-local + + computation-pure + computation-each + computation-each-in-list + computation-bind + computation-sequence + computation-forked + computation-bind/forked + + computation-fn + computation-with + computation-with! + + default-computation + + define-computation-type + make-hash-table + variable-comparator) + (begin + + ;; Box 模拟(暂时无 SRFI-111) + (define (box x) (cons x 'box)) + (define (unbox b) (car b)) + (define (set-box! b x) (set-car! b x)) + + (define-record-type + (make-environment-variable name default immutable? id) + computation-environment-variable? + (name environment-variable-name) + (default environment-variable-default) + (immutable? environment-variable-immutable?) + (id environment-variable-id)) + + (define make-computation-environment-variable + (let ((count 0)) + (lambda (name default immutable?) + (set! count (+ count 1)) + (make-environment-variable name default immutable? (- count))))) + + (define (computation-environment? obj) + (and (vector? obj) + (> (vector-length obj) 2) + (hash-table? (vector-ref obj 0)) + (list? (vector-ref obj 1)))) + + (define (predefined? var) + (not (negative? (environment-variable-id var)))) + + (define variable-comparator + (make-comparator computation-environment-variable? + eq? + (lambda (x y) + (< (environment-variable-id x) + (environment-variable-id y))) + (lambda (x . y) + (environment-variable-id x)))) + + ;; Alist 替代 mapping + (define (local-ref alist var default-thunk success) + (let ((pair (assq var alist))) + (if pair + (success (cdr pair)) + (default-thunk)))) + + (define (local-set alist var box) + (cons (cons var box) alist)) + + (define (local-for-each proc alist) + (for-each (lambda (p) (proc (car p) (cdr p))) alist)) + + (define (environment-global env) + (vector-ref env 0)) + + (define (environment-local env) + (vector-ref env 1)) + + (define (environment-set-global! env global) + (vector-set! env 0 global)) + + (define (environment-set-local! env local) + (vector-set! env 1 local)) + + (define (environment-cell-set! env var box) + (vector-set! env (+ 2 (environment-variable-id var)) box)) + + (define (environment-cell env var) + (vector-ref env (+ 2 (environment-variable-id var)))) + + (define default-computation + (make-computation-environment-variable 'default-computation #f #f)) + + (define-macro (define-computation-type make-environment run . vars) + (letrec ((process-vars + (lambda (vars n acc) + (if (null? vars) + (reverse acc) + (let ((v (car vars)) + (rest (cdr vars))) + (cond + ((and (pair? v) (pair? (cdr v)) (pair? (cddr v)) + (string=? (caddr v) "immutable")) + (let ((var (car v)) + (default (cadr v))) + (process-vars rest (+ n 1) + (cons (list var default #t n) acc)))) + ((and (pair? v) (pair? (cdr v))) + (let ((var (car v)) + (default (cadr v))) + (process-vars rest (+ n 1) + (cons (list var default #f n) acc)))) + (else + (process-vars rest (+ n 1) + (cons (list v #f #f n) acc))))))))) + (let* ((processed (process-vars vars 0 '())) + (n (length processed)) + (default-syms (map (lambda (x) (gensym "default")) processed)) + (env-sym (gensym "env"))) + `(begin + ,@(map (lambda (p ds) `(define ,ds ,(cadr p))) + processed default-syms) + ,@(map (lambda (p ds) + `(define ,(car p) + (,make-environment-variable ',(car p) ,ds ,(caddr p) ,(cadddr p)))) + processed default-syms) + (define (,make-environment) + (let ((,env-sym (make-vector ,(+ n 2)))) + (,environment-set-global! ,env-sym (make-hash-table variable-comparator)) + (,environment-set-local! ,env-sym '()) + ,@(map (lambda (p ds) + `(vector-set! ,env-sym ,(+ (cadddr p) 2) (,box ,ds))) + processed default-syms) + ,env-sym)) + (define (,run computation) + (,execute computation (,make-environment))))))) + + (define (computation-environment-ref env var) + (if (predefined? var) + (unbox (environment-cell env var)) + (local-ref + (environment-local env) + var + (lambda () + (hash-table-ref/default (environment-global env) + var + (environment-variable-default var))) + unbox))) + + (define (computation-environment-update env . arg*) + (let ((new-env (vector-copy env))) + (let loop ((arg* arg*) + (local (environment-local env))) + (if (null? arg*) + (begin + (environment-set-local! new-env local) + new-env) + (let ((var (car arg*)) + (val (cadr arg*))) + (if (predefined? var) + (begin + (environment-cell-set! new-env var (box val)) + (loop (cddr arg*) local)) + (loop (cddr arg*) (local-set local var (box val))))))))) + + ;; TODO: check immutable? + (define (computation-environment-update! env var val) + (if (predefined? var) + (set-box! (environment-cell env var) val) + (local-ref (environment-local env) + var + (lambda () + (hash-table-set! (environment-global env) var val)) + (lambda (cell) + (set-box! cell val))))) + + (define (computation-environment-copy env) + (let ((global (hash-table-copy (environment-global env) #t))) + (local-for-each (lambda (var cell) + (hash-table-set! global var (unbox cell))) + (environment-local env)) + (let ((new-env (make-vector (vector-length env)))) + (environment-set-global! new-env global) + (environment-set-local! new-env '()) + (do ((i (- (vector-length env) 1) (- i 1))) + ((< i 2) new-env) + (vector-set! new-env i (box (unbox (vector-ref env i)))))))) + + (define (execute computation env) + (let ((coerce (if (procedure? computation) + values + (or (computation-environment-ref env default-computation) + (error "not a computation" computation))))) + ((coerce computation) env))) + + (define (make-computation proc) + (lambda (env) + (proc (lambda (c) (execute c env))))) + + (define (computation-pure . args) + (make-computation + (lambda (compute) + (apply values args)))) + + (define (computation-each a . a*) + (computation-each-in-list (cons a a*))) + + (define (computation-each-in-list a*) + (make-computation + (lambda (compute) + (let loop ((a (car a*)) (a* (cdr a*))) + (if (null? a*) + (compute a) + (begin + (compute a) + (loop (car a*) (cdr a*)))))))) + + (define (computation-bind a . f*) + (make-computation + (lambda (compute) + (let loop ((a a) (f* f*)) + (if (null? f*) + (compute a) + (loop (call-with-values + (lambda () (compute a)) + (car f*)) + (cdr f*))))))) + + (define (computation-ask) + (lambda (env) + env)) + + (define (computation-local updater computation) + (lambda (env) + (computation (updater env)))) + + (define-macro (computation-fn . args) + (let ((clauses (car args)) + (body (cdr args))) + (define (parse-clauses clauses) + (map (lambda (c) + (if (pair? c) + (let ((id (car c)) + (var (cadr c))) + (list id var (gensym "tmp"))) + (let ((id c)) + (list id id (gensym "tmp"))))) + clauses)) + (let* ((parsed (parse-clauses clauses)) + (env-sym (gensym "env")) + (ids (map car parsed)) + (vars (map cadr parsed)) + (tmps (map caddr parsed))) + `(let ,(map list tmps vars) + (computation-bind + (computation-ask) + (lambda (,env-sym) + (let ,(map (lambda (id tmp) + `(,id (computation-environment-ref ,env-sym ,tmp))) + ids tmps) + ,@body))))))) + + (define-macro (computation-with . args) + (let ((bindings (car args)) + (comps (cdr args))) + (let ((var-tmps (map (lambda (b) (gensym "var")) bindings)) + (val-tmps (map (lambda (b) (gensym "val")) bindings)) + (comp-tmps (map (lambda (c) (gensym "comp")) comps))) + `(let ,(append (map (lambda (b vt) `(,vt ,(car b))) bindings var-tmps) + (map (lambda (b vt) `(,vt ,(cadr b))) bindings val-tmps) + (map (lambda (c ct) `(,ct ,c)) comps comp-tmps)) + (computation-local + (lambda (env) + (computation-environment-update env + ,@(apply append (map list var-tmps val-tmps)))) + (computation-each ,@comp-tmps)))))) + + (define-macro (computation-with! . bindings) + (let ((var-tmps (map (lambda (b) (gensym "var")) bindings)) + (val-tmps (map (lambda (b) (gensym "val")) bindings)) + (env-sym (gensym "env"))) + `(let ,(append (map (lambda (b vt) `(,vt ,(car b))) bindings var-tmps) + (map (lambda (b vt) `(,vt ,(cadr b))) bindings val-tmps)) + (computation-bind + (computation-ask) + (lambda (,env-sym) + ,@(map (lambda (vt val-t) + `(computation-environment-update! ,env-sym ,vt ,val-t)) + var-tmps val-tmps) + (computation-pure (if #f #f))))))) + + (define (computation-forked a . a*) + (make-computation + (lambda (compute) + (let loop ((a a) (a* a*)) + (if (null? a*) + (compute a) + (begin + (compute (computation-local + (lambda (env) + (computation-environment-copy env)) + a)) + (loop (car a*) (cdr a*)))))))) + + (define (computation-bind/forked computation . proc*) + (apply computation-bind + (computation-local computation-environment-copy computation) + proc*)) + + (define (computation-sequence fmt*) + (fold-right + (lambda (fmt res) + (computation-bind + res + (lambda (vals) + (computation-bind + fmt + (lambda (val) + (computation-pure (cons val vals))))))) + (computation-pure '()) fmt*)) + + (define-computation-type make-computation-environment computation-run))) + diff --git a/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-19.scm b/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-19.scm new file mode 100644 index 0000000000..95b7572180 --- /dev/null +++ b/TeXmacs/plugins/goldfish/goldfish/srfi/srfi-19.scm @@ -0,0 +1,680 @@ +; +; Copyright (C) 2026 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +;; +;; SRFI-19 Implementation for Goldfish Scheme +;; +;; This is a heavily modified implementation of SRFI-19 "Time Data Types +;; and Procedures". While based on the original reference implementation, +;; nearly every function has been rewritten for performance, clarity, or +;; to adapt to Goldfish Scheme's idioms. +;; +;; ====================================================================== +;; SRFI-19: Time Data Types and Procedures. +;; +;; Copyright (C) I/NET, Inc. (2000, 2002, 2003). All Rights Reserved. +;; +;; Permission is hereby granted, free of charge, to any person obtaining +;; a copy of this software and associated documentation files (the +;; "Software"), to deal in the Software without restriction, including +;; without limitation the rights to use, copy, modify, merge, publish, +;; distribute, sublicense, and/or sell copies of the Software, and to +;; permit persons to whom the Software is furnished to do so, subject to +;; the following conditions: +;; +;; The above copyright notice and this permission notice shall be +;; included in all copies or substantial portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +(define-library (srfi srfi-19) + (import (rename (scheme time) + (get-time-of-day glue:get-time-of-day) + (monotonic-nanosecond glue:monotonic-nanosecond)) + (only (srfi srfi-13) string-pad string-tokenize string-trim-right) + (only (srfi srfi-8) receive) + (only (scheme base) open-output-string open-input-string get-output-string + floor/) + (liii error)) + (export + ;; Constants + TIME-DURATION TIME-MONOTONIC TIME-PROCESS + TIME-TAI TIME-THREAD TIME-UTC + ;; Time object and accessors + make-time time? + time-type time-nanosecond time-second + set-time-type! set-time-nanosecond! set-time-second! + copy-time + ;; Time comparison procedures + time<=? time=? time>? + ;; Time arithmetic procedures + time-difference + ;; Current time and clock resolution + current-date current-julian-day current-time time-resolution + ;; Date object and accessors + make-date date? + date-nanosecond date-second date-minute date-hour + date-day date-month date-year date-zone-offset + date-year-day + date-week-day date-week-number + ;; Time/Date/Julian Day/Modified Julian Day Converters + time-utc->date date->time-utc + ;; Date to String/String to Date Converters + date->string) + (begin + + ;; ==================== + ;; Constants + ;; ==================== + + (define TIME-DURATION 'time-duration) + (define TIME-MONOTONIC 'time-monotonic) + (define TIME-PROCESS 'time-process) + (define TIME-TAI 'time-tai) + (define TIME-THREAD 'time-thread) + (define TIME-UTC 'time-utc) + + (define priv:LOCALE-DECIMAL-POINT ".") + + (define priv:LOCALE-ABBR-WEEKDAY-VECTOR (vector "Sun" "Mon" "Tue" "Wed" + "Thu" "Fri" "Sat")) + (define priv:LOCALE-LONG-WEEKDAY-VECTOR (vector "Sunday" "Monday" + "Tuesday" "Wednesday" + "Thursday" "Friday" + "Saturday")) + ;; note empty string in 0th place. + (define priv:LOCALE-ABBR-MONTH-VECTOR (vector "" "Jan" "Feb" "Mar" + "Apr" "May" "Jun" "Jul" + "Aug" "Sep" "Oct" "Nov" + "Dec")) + (define priv:LOCALE-LONG-MONTH-VECTOR (vector "" "January" "February" + "March" "April" "May" + "June" "July" "August" + "September" "October" + "November" "December")) + + (define priv:LOCALE-PM "PM") + (define priv:LOCALE-AM "AM") + + ;; See `date->string` below + (define priv:LOCALE-DATE-TIME-FORMAT "~a ~b ~d ~H:~M:~S~z ~Y") + (define priv:LOCALE-SHORT-DATE-FORMAT "~m/~d/~y") + (define priv:LOCALE-TIME-FORMAT "~H:~M:~S") + (define priv:ISO-8601-DATE-TIME-FORMAT "~Y-~m-~dT~H:~M:~S~z") + + (define priv:NANO (expt 10 9)) + (define priv:SID 86400) ; seconds in a day + (define priv:SIHD 43200) ; seconds in a half day + (define priv:TAI-EPOCH-IN-JD 4881175/2) ; julian day number for 'the epoch' + + ;; ==================== + ;; Time object and accessors + ;; ==================== + + (define-record-type