83 Commits 0db4137a34 ... 158a930c64

Author SHA1 Message Date
  mizusato 158a930c64 update docs 1 year ago
  mizusato f274b1b888 update docs 1 year ago
  mizusato 72b44c681c add docs images 1 year ago
  mizusato 80dfd53732 update docs 1 year ago
  mizusato 091857d33e update docs 1 year ago
  mizusato 01bbe60695 update docs 1 year ago
  mizusato ac6b023dc8 update docs 1 year ago
  mizusato d0424c6844 update docs 1 year ago
  mizusato df474cc2e7 fix 1 year ago
  mizusato b3f104944b update docs 1 year ago
  mizusato a1a14dbae8 update docs 1 year ago
  mizusato 0c0269fdfb adjust 1 year ago
  mizusato 711d2d9fba update docs 1 year ago
  mizusato 61febb9934 fix 1 year ago
  mizusato 53ef4b6397 update docs 1 year ago
  mizusato c9a5046ed6 update docs 1 year ago
  mizusato 560abe0f33 update docs 1 year ago
  mizusato 3365f82a30 update docs 1 year ago
  mizusato 275213bdfc adjust 1 year ago
  mizusato 5eb1e29296 fix 1 year ago
  mizusato 3b61674667 update docs 1 year ago
  mizusato 373819bb01 update docs 1 year ago
  mizusato 76b89e17b1 update docs 1 year ago
  mizusato 3d96278515 update docs 1 year ago
  mizusato 3cd456b1cc update docs 1 year ago
  mizusato bb72d8d14c fix 1 year ago
  mizusato 4328f16148 update docs 1 year ago
  mizusato 05ebe763c0 update docs 1 year ago
  mizusato 1f3ccc1389 update docs 1 year ago
  mizusato a16539db82 update docs 1 year ago
  mizusato 793f627057 update docs 1 year ago
  mizusato 410fade87b update docs 1 year ago
  mizusato 8af93e2b81 lazy reloadable 1 year ago
  mizusato 51fc3292d8 refactor 1 year ago
  mizusato 4eace7a13c update docs 1 year ago
  mizusato 5a82200f0c update docs 1 year ago
  mizusato 324e3de25a update docs 1 year ago
  mizusato 87e1c07b0c adjust 1 year ago
  mizusato 56befc67d2 update docs 1 year ago
  mizusato 4002f35482 update docs 1 year ago
  mizusato 0190c3d9f6 adjust 1 year ago
  mizusato 14423c06cb update docs 1 year ago
  mizusato fa72000679 update docs 1 year ago
  mizusato 138cb39b30 fix typo 1 year ago
  mizusato d641369bf2 update docs 1 year ago
  mizusato 93644f68df fix 1 year ago
  mizusato 858925d4d8 update docs 1 year ago
  mizusato e62a61ab63 update docs 1 year ago
  mizusato b57405716e add doc images 1 year ago
  mizusato 27ec9543e3 update docs 1 year ago
  mizusato e3c327dacf update docs 1 year ago
  mizusato 279a03fe15 update docs 1 year ago
  mizusato 2c0579b5d3 update docs 1 year ago
  mizusato 9f9712e348 fix 1 year ago
  mizusato ef04999160 fix 1 year ago
  mizusato fdeb74b9ef scroll area margins 1 year ago
  mizusato 84dd796038 update docs 1 year ago
  mizusato 93f744dc0c update docs 1 year ago
  mizusato ba78d241c6 update docs 1 year ago
  mizusato 40c5004bc7 fix 1 year ago
  mizusato eea53e44e8 fix 1 year ago
  mizusato c3901c57e3 fix 1 year ago
  mizusato 36f9bc18c2 fix 1 year ago
  mizusato a2b9c815b5 fix 1 year ago
  mizusato 64ea17e095 update docs 1 year ago
  mizusato 03dad10ef7 update docs 1 year ago
  mizusato 8cdb2b1ed3 update docs 1 year ago
  mizusato 1c412809cf add doc images 1 year ago
  mizusato 5da30ab597 update docs 1 year ago
  mizusato 07b38a3f2b update docs 1 year ago
  mizusato acf8d4e67d update docs 1 year ago
  mizusato 28dd4d2b59 update docs 1 year ago
  mizusato 7d23e8d6c5 update docs 1 year ago
  mizusato 9bf258924c update docs 1 year ago
  mizusato c70175c8d7 update docs 1 year ago
  mizusato 0579e8bd54 update docs 1 year ago
  mizusato a9d1a7a94e update docs 1 year ago
  mizusato ecce2410df update docs 1 year ago
  mizusato c54f5c212c add doc images 1 year ago
  mizusato 700e17d611 update docs 1 year ago
  mizusato 3984265541 update docs 1 year ago
  mizusato 7f75ecd192 update docs 1 year ago
  mizusato 4dc1996776 add doc images 1 year ago

+ 2 - 0
.idea/KumaChan.iml

@@ -5,6 +5,8 @@
     <content url="file://$MODULE_DIR$">
       <excludeFolder url="file://$MODULE_DIR$/build" />
       <excludeFolder url="file://$MODULE_DIR$/runtime/lib/ui/qt/build" />
+      <excludeFolder url="file://$MODULE_DIR$/docs/build" />
+      <excludeFolder url="file://$MODULE_DIR$/standalone/qt/build" />
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />

+ 106 - 0
docs/source/api/arithmetic.rst

@@ -0,0 +1,106 @@
+Arithmetic
+++++++++++
+
+API
+===
+
+Ordering
+--------
+
+.. code-block:: none
+
+    type Ordering(~String) enum { L<R, L=R, L>R }
+    operator == { o1 Ordering, o2 Ordering } Bool
+
+.. code-block:: none
+
+    type == [T] interface { Operator Lambda[Pair[T,T],Bool] }
+    type <  [T] interface { Operator Lambda[Pair[T,T],Bool] }
+    type <> [T] interface { Operator Lambda[Pair[T,T],Ordering] }
+
+.. code-block:: none
+
+    operator != [T] { a T, b T } { T/== ==[T] } Bool
+    operator >  [T] { a T, b T } { T/< <[T] }   Bool
+    operator <= [T] { a T, b T } { T/< <[T] }   Bool
+    operator >= [T] { a T, b T } { T/< <[T] }   Bool
+    function Min[T] { a T, b T } { T/< <[T] }   T
+    function Max[T] { a T, b T } { T/< <[T] }   T
+
+Int
+---
+
+.. code-block:: none
+
+    type Int(~String) native
+
+.. code-block:: none
+
+    operator + { a Int, b Int } Int
+    operator - { a Int, b Int } Int
+    operator * { a Int, b Int } Int
+    operator / { a Int, b Int } Int
+    operator % { a Int, b Int } Int
+    operator ^ { a Int, b Int } Int
+
+.. code-block:: none
+
+    operator == { a Int, b Int } Bool
+    operator <  { a Int, b Int } Bool
+    operator <> { a Int, b Int } Ordering
+
+Float
+-----
+
+.. code-block:: none
+
+    type Float(~String) native
+
+.. code-block:: none
+
+    operator + { x Float, y Float } Float
+    operator - { x Float, y Float } Float
+    operator * { x Float, y Float } Float
+    operator / { x Float, y Float } Float
+    operator % { x Float, y Float } Float
+    operator ^ { x Float, y Float } Float
+
+.. code-block:: none
+
+    operator == { x Float, y Float } Bool
+    operator <  { x Float, y Float } Bool
+
+.. code-block:: none
+
+    method Float.Int Int
+    method Int.Float Float
+
+.. code-block:: none
+
+    const NaN Float
+    const +Inf Float
+    const -Inf Float
+    method Float.Normal   Bool
+    method Float.NaN      Bool
+    method Float.Infinite Bool
+
+.. code-block:: none
+
+    const E  Float
+    const PI Float
+    function Floor { x Float } Float
+    function Ceil  { x Float } Float
+    function Round { x Float } Float
+    function Sqrt  { x Float } Float
+    function Cbrt  { x Float } Float
+    function Exp   { x Float } Float
+    function Log   { x Float } Float
+    function Sin   { x Float } Float
+    function Cos   { x Float } Float
+    function Tan   { x Float } Float
+    function Asin  { x Float } Float
+    function Acos  { x Float } Float
+    function Atan  { x Float } Float
+    function Atan2 { y Float, x Float } Float
+
+

+ 168 - 0
docs/source/api/collections.rst

@@ -0,0 +1,168 @@
+Collections
++++++++++++
+
+API
+===
+
+List
+----
+
+.. code-block:: none
+
+    type List[T] native
+
+.. code-block:: none
+
+    function variadic List[T] { items List[T] } List[T]
+    function variadic ListConcat[T] { lists List[List[T]] } List[T]
+
+.. code-block:: none
+
+    function Cons[T] { head T, tail List[T] } List[T]
+    function Count { n Int } List[Int]
+
+.. code-block:: none
+
+    method List.Empty Bool
+    method List.First Maybe[T]
+    method List.Length Int
+    method List.Seq Seq[T]
+    method List.$ $[T]
+
+.. code-block:: none
+
+    operator shift[T]   { l List[T] } Maybe[Pair[T,List[T]]]
+    operator prepend[T] { l List[T], item T } List[T]
+    operator reverse[T] { l List[T] } List[T]
+    operator sort[T] { l List[T] } { T/< <[T] } List[T]
+    operator take[T] { l List[T], n Int } List[T]
+    operator with-index[T] { l List[T] } List[Pair[T,Int]]
+    operator map[A,B]  { l List[A], f Lambda[A,B] } List[B]
+    operator map?[A,B] { l List[A], f Lambda[A,Maybe[B]] } List[B]
+    operator map*[A,B] { l List[A], f Lambda[A,List[B]] } List[B]
+    operator filter[T] { l List[T], f Lambda[T,Bool] } List[T]
+    operator scan[A,B] { l List[A], v B, f Lambda[Pair[B,A],B] } List[B]
+    operator fold[A,B] { l List[A], v B, f Lambda[Pair[B,A],B] } B
+
+Seq
+---
+
+.. code-block:: none
+
+    type Seq[T] native
+
+.. code-block:: none
+
+    function variadic Seq[T] { items List[T] } Seq[T]
+
+.. code-block:: none
+
+    method Seq.Empty Bool
+    method Seq.Last Maybe[T]
+    method Seq.Length Int
+    method Seq.List List[T]
+
+.. code-block:: none
+
+    operator append[T] { s Seq[T], item T } Seq[T]
+    operator append?[T] { s Seq[T], item? Maybe[T] } Seq[T]
+    operator append*[T] { s Seq[T], items List[T] } Seq[T]
+    operator sort[T] { s Seq[T] } { T/< <[T] } Seq[T]
+    operator filter[T] { s Seq[T], f Lambda[T,Bool] } Seq[T]
+
+Queue
+-----
+
+.. code-block:: none
+
+    type Queue[T] native
+
+.. code-block:: none
+
+    function variadic Queue[T] { items List[T] } Queue[T]
+
+.. code-block:: none
+
+    method Queue.Empty Bool
+    method Queue.Size  Int
+    method Queue.First Maybe[T]
+    method Queue.List List[T]
+
+.. code-block:: none
+
+    operator shift[T]  { q Queue[T] } Maybe[Pair[T,Queue[T]]]
+    operator append[T] { q Queue[T], item T } Queue[T]
+
+Heap
+----
+
+.. code-block:: none
+
+    type Heap[T] native
+
+.. code-block:: none
+
+    function variadic Heap[T] { items List[T] } { T/< <[T] } Heap[T]
+
+.. code-block:: none
+
+    method Heap.Empty Bool
+    method Heap.Size  Int
+    method Heap.First Maybe[T]
+    method Heap.List List[T]
+
+.. code-block:: none
+
+    operator shift[T]  { h Heap[T] } Maybe[Pair[T,Heap[T]]]
+    operator insert[T] { h Heap[T], item T } Heap[T]
+
+Set
+---
+
+.. code-block:: none
+
+    type Set[T] native
+
+.. code-block:: none
+
+    function variadic Set[T] { items List[T] } { T/<> <>[T] } Set[T]
+
+.. code-block:: none
+
+    method Set.Empty Bool
+    method Set.Size  Int
+    method Set.List List[T]
+
+.. code-block:: none
+
+    operator has[T] { s Set[T], item T } Bool
+    operator delete[T] { s Set[T], item T } Set[T]
+    operator insert[T] { s Set[T], item T } Set[T]
+
+Map
+---
+
+.. code-block:: none
+
+    type Map[K,V] native
+
+.. code-block:: none
+
+    function variadic Map[K,V] { entries List[Pair[K,V]] } { K/<> <>[K] } Map[K,V]
+
+.. code-block:: none
+
+    method Map.Empty Bool
+    method Map.Size  Int
+    method Map.Keys    List[K]
+    method Map.Values  List[V]
+    method Map.Entries List[Pair[K,V]]
+
+.. code-block:: none
+
+    operator has[K,V] { m Map[K,V], key K } Bool
+    operator lookup[K,V] { m Map[K,V], key K } Maybe[V]
+    operator delete[K,V] { m Map[K,V], key K } Map[K,V]
+    operator insert[K,V] { m Map[K,V], pair Pair[K,V] } Map[K,V]
+
+

+ 23 - 0
docs/source/api/debugging.rst

@@ -0,0 +1,23 @@
+Debugging
++++++++++
+
+API
+===
+
+.. code-block:: none
+
+    function DebugInspect[T] { hint String, v IntoReflectValue[T] } T
+
+.. code-block:: none
+
+    function DebugExpose[T] { name String, v IntoReflectValue[T] } $[Null]
+
+.. code-block:: none
+
+    function DebugTrace[T] { hint String, o IntoReflectValue[$[T]] } $[T]
+
+.. code-block:: none
+
+    function DebugWatch[T] { hint String, o IntoReflectValue[$[T]] } $[Null]
+
+

+ 100 - 0
docs/source/api/io.rst

@@ -0,0 +1,100 @@
+I/O
++++
+
+API
+===
+
+Bytes
+-----
+
+.. code-block:: none
+
+    type Bytes native
+
+Currently there is no API for the ``Bytes`` type.
+
+Serialization
+-------------
+
+.. code-block:: none
+
+    function Serialize[T] { v IntoReflectValue[T] } $[String]
+    function Deserialize[T] { s String, t IntoReflectType[T] } $[T]
+
+Time
+----
+
+.. code-block:: none
+
+    type Time(~String) native
+
+.. code-block:: none
+
+    const Now $[Time]
+
+.. code-block:: none
+
+    method Time.String String
+
+.. code-block:: none
+
+    operator -ms { t Time, u Time } Int
+
+.. code-block:: none
+
+    function TimeOf[T] { o $[T] } $[Time]
+    operator with-time[T] { o $[T] } $[Pair[T,Time]]
+
+Process
+-------
+
+.. code-block:: none
+
+    const Arguments List[String]  // without interpreter arguments and program name
+    const Environment List[String]
+
+File
+----
+
+.. code-block:: none
+
+    type File(~String) native
+
+.. code-block:: none
+
+    method File.String String
+
+.. code-block:: none
+
+    operator == { f File, g File } Bool
+
+.. code-block:: none
+
+    function ReadTextFile { f File } $[String]
+    function WriteTextFile { f File, text String } $[Null]
+
+Config
+------
+
+.. code-block:: none
+
+    function ReadConfig[T] { dir String, name String, default IntoReflectValue[T] } $[T]
+    function WriteConfig[T] { dir String, name String, value IntoReflectValue[T] } $[Null]
+
+Path of config file is as follows.
+
+* Linux: $HOME/.config/``dir``/``name``
+* Windows: %AppData%/``dir``/``name``
+
+Request
+-------
+
+.. code-block:: none
+
+    function Get[Resp] { endpoint String, t IntoReflectType[Resp], token String('') } $[Resp]
+    function Post[Req,Resp] { data IntoReflectValue[Req], endpoint String, t IntoReflectType[Resp], token String('') } $[Resp]
+    function Put[Req,Resp] { data IntoReflectValue[Req], endpoint String, t IntoReflectType[Resp], token String('') } $[Resp]
+    function Delete[Resp] { endpoint String, t IntoReflectType[Resp], token String('') } $[Resp]
+    function Subscribe[Resp] { endpoint String, t IntoReflectType[Resp], token String('') } $[Resp]
+
+

+ 236 - 0
docs/source/api/json.km

@@ -0,0 +1,236 @@
+namespace json ::
+
+
+type Value union {
+    Null,
+    Bool,
+    Float,
+    String,
+    List[Value],
+    Map[String,Value]
+}
+
+function Stringify { v Value } String {
+    when (v) {
+        Null => 'null',
+        Bool p => if (p) { 'true' } else { 'false' },
+        Float x => x.String,
+        String s => Quote(s),
+        List l => String('[', { l | map(Stringify) | join(',') }, ']'),
+        Map m => String('{',
+            m.Entries
+            | map({ (k,v) => String(Quote(k), ':', Stringify(v)) })
+            | join(','),
+        '}')
+    }
+}
+
+function Parse { s String } Result[Value] {
+    let text = new text {
+        Position:  0,
+        Remaining: s
+    },
+    let result = <value>.Parse(text),
+    when (result) {
+        OK (v, text) => {
+            let text = { text | trim() },
+            if (text.Remaining.Empty) { v }
+            else { Error('expect EOF at position ', text.Position) }
+        },
+        Error e => e
+    }
+}
+
+entry {
+    const v = ([Value]) Map[String,Value](
+        Pair('a', 'foo'),
+        Pair('b', 42.0),
+        Pair('c', List[Value](Null, Yes, No, 0.5, 'abc'))
+    ),
+    @await input = GetText(String('text: (e.g.',Stringify(v),')')),
+    when(Parse(input)) {
+        OK s => ShowInfo(Stringify(s)),
+        Error e => ShowCritical(e.Message)
+    }
+}
+
+
+const <value> parser[Value] {
+    choice(
+        Pair('n', <null>),
+        Pair('tf', <boolean>),
+        Pair('-0123456789', <number>),
+        Pair('"', <string>),
+        Pair('[', <array>),
+        Pair('{', <object>)
+    )
+}
+const <null> parser[Value] {
+    transform('null', 'null', { => ([Value]) Null })
+}
+const <boolean> parser[Value] {
+    transform('boolean', 'true|false', { s =>
+        if ((s == 'true')) { ([Value]) Yes }
+        else { ([Value]) No }
+    })
+}
+const <number> parser[Value] {
+    transform('number', '-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?', { s =>
+        if (let x = ParseFloat(s)) { ([Value]) x }
+        else { Error('invalid number') }
+    })
+}
+const <string> parser[Value] {
+    (<string*> map { s => ([Value]) s })
+}
+const <string*> parser[String] {
+    transform('string', '"(?:[^"\\]|\\u\d{4}|\\["\\\/bfnrt]|)*"', { s =>
+        if (let unquoted = Unquote(s)) { unquoted }
+        else { Error('invalid string') }
+    })
+}
+const <array> parser[Value] {
+    @compose consume('\['),
+    @compose items = sequence(<value>, consume(',')),
+    @compose consume('\]'),
+    return! (items)
+}
+const <object> parser[Value] {
+    @compose consume('{'),
+    @compose entries = sequence(<key-value>, consume(',')),
+    @compose consume('}'),
+    return! (Map{entries})
+}
+const <key-value> parser[Pair[String,Value]] {
+    @compose key = <string*>,
+    @compose consume(':'),
+    @compose value = <value>,
+    return! (Pair(key, value))
+}
+
+type text record {
+    Position  Int,
+    Remaining String
+}
+method text.FirstChar Maybe[Char] {
+    this.Remaining.FirstChar
+}
+operator trim { text text } text {
+    (((text advance '[ \t\r\n]+') map { (_,text) => text }) ?? text)
+}
+operator advance { text text, pattern RegExp } Maybe[Pair[String,text]] {
+    if (let (match, remaining) = (text.Remaining advance pattern)) {
+        Pair(match, new text {
+            Position:  (text.Position + match.NumberOfChars),
+            Remaining: remaining
+        })
+    } else {
+        Null
+    }
+}
+
+type parser[T] interface { Parse Lambda[text,Result[Pair[T,text]]] }
+function return![T] { v T } parser[T] {
+    new parser0(v)
+}
+function consume { pattern RegExp } parser[Null] {
+    new parser1 {
+        Name: { pattern.String | replace('\\', { => '' }) },
+        Pattern: pattern,
+        GetValue: { => Null }
+    }
+}
+function transform[T] { name String, pattern RegExp, k Lambda[String,Result[T]] } parser[T] {
+    new parser1 {
+        Name: name,
+        Pattern: pattern,
+        GetValue: k
+    }
+}
+function variadic choice[T] { branches List[Pair[String,parser[T]]] } parser[T] {
+    let entries = (branches map* { (k,v) => (k.Chars map { ch => Pair(ch,v) }) }),
+    new parser2(Map{entries})
+}
+function sequence[T] { item parser[T], sep parser[Null] } parser[List[T]] {
+    item | repeat(sep)
+}
+
+operator map[A,B] { p parser[A], f Lambda[A,B] } parser[B] {
+    { text =>
+        when (p(text)) {
+            OK (a,remaining) => Pair(f(a), remaining),
+            Error e => e
+        }
+    }
+}
+operator compose[A,B] { p parser[A], f Lambda[A,parser[B]] } parser[B] {
+    { text => {
+        when (p(text)) {
+            OK (a,remaining) => f(a)(remaining),
+            Error e => e
+        }
+    }}
+}
+operator repeat[T] { p parser[T], sep parser[Null] } parser[List[T]] {
+    let tail-parser = ([parser[List[T]]]) { text &recurse => {
+        let recurse = ([parser[List[T]]]) recurse,
+        when (sep(text)) {
+        OK (_,text) => {
+            when (p(text)) {
+            OK (t,remaining) =>
+                (recurse map { tail => Cons(t, tail) })(remaining),
+            Error err =>
+                err
+            }
+        },
+        Error =>
+            Pair(List[T](), text)
+        }
+    }},
+    { text => {
+        when (p(text)) {
+        OK (t,remaining) =>
+            (tail-parser map { tail => Cons(t, tail) })(remaining),
+        Error =>
+            Pair(List[T](), text)
+        }
+    }}
+}
+
+type parser0[T] (parser) record {
+    Value T
+}
+method parser0.Parse Lambda[text,Result[Pair[T,text]]] {
+    { text => Pair(this.Value, text) }
+}
+type parser1[T] (parser) record {
+    Name String,
+    Pattern RegExp,
+    GetValue Lambda[String,Result[T]]
+}
+method parser1.Parse Lambda[text,Result[Pair[T,text]]] {
+    { text => {
+        let text = { text | trim() },
+        if (let (match,remaining) = (text advance this.Pattern)) {
+            when (this.GetValue(match)) {
+                OK t => Pair(t, remaining),
+                Error e => e
+            }
+        } else {
+            Error('expect ', this.Name, ' at position ', text.Position)
+        }
+    }}
+}
+type parser2[T] (parser) record {
+    Mapping Map[Char,parser[T]]
+}
+method parser2.Parse Lambda[text,Result[Pair[T,text]]] {
+    { text => {
+        let text = { text | trim() },
+        if (let c = text.FirstChar, let p = (this.Mapping lookup c)) {
+            p(text)
+        } else {
+            Error('bad text at position ', text.Position)
+        }
+    }}
+}

+ 134 - 0
docs/source/api/rx.rst

@@ -0,0 +1,134 @@
+Observable & Subject
+++++++++++++++++++++
+
+API
+===
+
+Observable
+----------
+
+.. code-block:: none
+
+    type $[T] native  // Observable
+
+.. code-block:: none
+
+    function variadic $[T] { items List[T] } $[T]
+    function variadic return[T] { items List[T] } $[T]  // equivalent to "$"
+    function variadic Merge[T] { items List[$[T]] } $[T]
+    function variadic Concat[T] { items List[$[T]] } $[T]
+    function StartWith[T] { v T, o $[T] } $[T]
+    function WithChildContext[T] { o $[T] } $[T]
+    function WithCancelTrigger[T] { cancel $[Null], o $[T] } $[T]
+    function WithCancelTimeout[T] { ms Int, o $[T] } $[T]
+
+.. code-block:: none
+
+    function SetTimeout { ms Int } $[Null]
+    function SetInterval { ms Int, n Int(-1) } $[Int]
+
+.. code-block:: none
+
+    const UUID $[String]
+    function Random { supremum Int } $[Int]
+    function Shuffle[T] { l List[T] } $[List[T]]
+
+.. code-block:: none
+
+    const NumCPU Int
+    function Go[T] { k Lambda[Null,T] } $[T]
+    function ForkJoin[T] { items List[$[T]], n Int(NumCPU) } $[List[T]]
+    operator concurrent[T] { l List[$[T]], n Int(NumCPU) } $[T]
+    operator concurrent-map[A,B] { o $[A], f Lambda[A,$[B]], n Int(NumCPU) } $[B]
+    operator fork-join[T] { l List[$[T]], n Int(NumCPU) } $[List[T]]
+    operator fork-join[A,B] { a $[A], b $[B], n Int(NumCPU) } $[Pair[A,B]]
+
+.. code-block:: none
+
+    method $.Result $[Result[T]]
+    function Throw[T] { err Error } $[T]
+    function Crash[T] { err Error } $[T]
+    operator catch[T] { o $[T], f Lambda[Pair[Error,$[T]],$[T]] } $[T]
+    operator retry[T] { o $[T], n Int(-1) } $[T]
+    operator log-error[T] { o $[T] } $[T]
+
+.. code-block:: none
+
+    operator distinct-until-changed[T] { o $[T] } { T/== ==[T] } $[T]
+    operator with-latest-from[T,X] { o $[T], x $[X] } $[Pair[T,X]]
+    operator map-to-latest-from[X] { o $[Null], x $[X] } $[X]
+    operator with-cycle[T,X] { o $[T], l List[X] } $[Pair[T,X]]
+    operator with-index[T] { o $[T] } $[Pair[T,Int]]
+    operator delay-subscription[T] { o $[T], ms Int } $[T]
+    operator delay-values[T] { o $[T], ms Int } $[T]
+    operator start-with[T] { o $[T], item T } $[T]
+    operator end-with[T]   { o $[T], item T } $[T]
+    operator throttle[T] { o $[T], f Lambda[T,$[Null]] } $[T]
+    operator debounce[T] { o $[T], f Lambda[T,$[Null]] } $[T]
+    operator throttle-time[T] { o $[T], ms Int } $[T]
+    operator debounce-time[T] { o $[T], ms Int } $[T]
+    operator complete-on-emit[T] { o $[T] } $[Null]
+    operator skip[T] { o $[T], n Int } $[T]
+    operator take[T] { o $[T], n Int } $[T]
+    operator take-last[T] { o $[T] } $[T]
+    operator take-last?[T] { o $[T] } $[Maybe[T]]
+    operator take-while[T] { o $[T], f Lambda[T,Bool] }
+    operator take-while?[T] { o $[Maybe[T]] } $[T]
+    operator take-until[T] { o $[T], stop $[Null] } $[T]
+    operator count[T] { o $[T] } $[Int]
+    operator collect[T] { o $[T], n Int(-1) } $[List[T]]
+    operator buffer-time[T] { o $[T], ms Int } $[List[T]]
+    operator pairwise[T] { o $[T] } $[Pair[T,T]]
+    operator buffer-count[T] { o $[T], n Int } $[Queue[T]]
+    operator map[A,B] { o $[A], f Lambda[A,B] } $[B]
+    operator map-to[A,B] { o $[A], v B } $[B]
+    operator filter[T] { o $[T], f Lambda[T,Bool] } $[T]
+    operator scan[A,B] { o $[A], v B, f Lambda[Pair[B,A],B] } $[B]
+    operator reduce[A,B] { o $[A], v B, f Lambda[Pair[B,A],B] } $[B]
+    operator combine-latest[A,B] { a $[A], b $[B] } $[Pair[A,B]]
+    operator combine-latest[T] { l List[$[T]] } $[List[T]]
+    operator await[A,B] { o $[A], k Lambda[A,$[B]] } $[B]
+    operator await-noexcept[A,B] { o $[A], k Lambda[A,$[B]] } $[B]
+    operator then[T] { o $[Null], k $[T] } $[T]
+    operator with[T] { o $[T], bg $[Null] } $[T]
+    operator and[T] { o $[T], bg $[Null] } $[T]
+    operator auto-map[A,B] { o $[A], f Lambda[A,$[B]] } $[B]
+    operator merge[T]  { l List[$[T]] } $[T]
+    operator concat[T] { l List[$[T]] } $[T]
+    operator merge[T]  { o1 $[T], o2 $[T] } $[T]
+    operator concat[T] { o1 $[T], o2 $[T] } $[T]
+    operator merge-map[A,B]   { o $[A], f Lambda[A,$[B]] } $[B]
+    operator concat-map[A,B]  { o $[A], f Lambda[A,$[B]] } $[B]
+    operator switch-map[A,B]  { o $[A], f Lambda[A,$[B]] } $[B]
+    operator exhaust-map[A,B] { o $[A], f Lambda[A,$[B]] } $[B]
+
+Subject
+-------
+
+.. code-block:: none
+
+    type Subject[T] native
+
+.. code-block:: none
+    
+    function variadic CreateSubject[T] { replay Int(0), items List[T] } $[Subject[T]]
+
+.. code-block:: none
+
+    method Subject.Values $[T]
+    method Subject.$ $[T]  // equivalent to "Values"
+
+.. code-block:: none
+
+    operator plug[T] { s Subject[T], o $[T] } $[Null]
+    operator push [T] { s Subject[T], v T } $[Null]
+    operator << [T] { s Subject[T], o $[T] } $[Null]  // equivalent to "plug"
+    operator <- [T] { s Subject[T], v T } $[Null]  // equivalent to "push"
+
+.. code-block:: none
+
+    function Multicast[T] { o $[T] } $[$[T]]
+    function Loopback[T] { k Lambda[$[T],$[T]] } $[T]
+    function SkipSync[T] { o $[T] } $[T]
+
+

+ 74 - 0
docs/source/api/sdi.km

@@ -0,0 +1,74 @@
+namespace ::
+
+entry {
+    @await bus = CreateSubject[EditorDocument[String]] {},
+    @auto-map doc = StartWith(EmptyDoc, bus.Values),
+    ShowNewEditorWindow(doc, bus)
+}
+const EmptyDoc EditorDocument[String] {
+    EditorDocument(Null, '')
+}
+function ShowNewEditorWindow { doc EditorDocument[String], bus Subject[EditorDocument[String]] } $[Null] {
+    ShowWindow({
+        @use e = Editor {
+            initial: doc,
+            content: { text => {
+                @use a = TextArea(text),
+                EditorView(a.Widget, a.Text)
+            }},
+            open: { modified => {
+                @await f = GetFileToOpen('Text (*.txt)'),
+                @catch (err, _) = ([$[EditorDocument[String]]]) {
+                    @await text = ReadTextFile(f),
+                    let doc = EditorDocument(f, text),
+                    if (modified) {
+                        @await (bus <- doc),
+                        return ()
+                    } else {
+                        return (doc)
+                    }
+                },
+                @await ShowCritical(err.Message),
+                return ()
+            }},
+            save: { (f?,text) => {
+                @await f = if (let f = f?) { $(f) }
+                           else { GetFileToSave('Text (*.txt)') },
+                @catch (err, _) = {
+                    @await WriteTextFile(f, text),
+                    return (Just(f))
+                },
+                @await ShowCritical(err.Message),
+                return ()
+            }}
+        },
+        @use create = Action(Icon('document-new'), 'New', 'Ctrl+N'),
+        @use open = Action(Icon('document-open'), 'Open', 'Ctrl+O'),
+        @use save = Action(Icon('document-save'), 'Save', 'Ctrl+S'),
+        @use save-as = Action(Icon('document-save-as'), 'Save As', 'Ctrl+Shift+S'),
+        @use Effect((bus << (create.Triggers map-to EmptyDoc))),
+        @use Effect((e bind-open open.Triggers)),
+        @use Effect((e bind-save save.Triggers)),
+        @use Effect((e bind-save-as save-as.Triggers)),
+        let title = {
+            @map (modified,file?) = (e.Modified combine-latest e.File),
+            let file-desc = file? | map({ f => f.String }) | ??('Untitiled'),
+            let modified-desc = if (modified) { '*' } else { '' },
+            String('Text Editor - ', file-desc, modified-desc)
+        },
+        let layout = Column(e.Widget),
+        let tool-bar = ToolBar(TextBesideIcon, create, open, save, save-as),
+        Window { title, layout, tool-bar, exit: { closes => {
+            @exhaust-map (_,modified) = (closes with-latest-from e.Modified),
+            if (modified) {
+                @await op = ShowSaveDiscardCancel('Document has unsaved changes.'),
+                when (op) {
+                    Save => e.Save,
+                    Discard => return (Null)
+                }
+            } else {
+                return (Null)
+            }
+        }}}
+    })
+}

BIN
docs/source/api/sdi.png


+ 0 - 0
docs/source/api/string.rst


Some files were not shown because too many files changed in this diff