Skip to content

Commit 8839673

Browse files
committed
Fix broken links in guide & support links to pseudo-constructors
1 parent a4eee7a commit 8839673

File tree

2 files changed

+54
-19
lines changed

2 files changed

+54
-19
lines changed

coroutines-guide.md

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ main: Now I can quit.
343343
<!--- TEST -->
344344

345345
As soon as main invokes `job.cancel`, we don't see any output from the other coroutine because it was cancelled.
346-
There is also an extension function [cancelAndJoin] that combines [cancel] and [join] invocations.
346+
There is also a [Job] extension function [cancelAndJoin]
347+
that combines [cancel][Job.cancel] and [join][Job.join] invocations.
347348

348349
### Cancellation is cooperative
349350

@@ -458,8 +459,8 @@ fun main(args: Array<String>) = runBlocking<Unit> {
458459

459460
> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-04.kt)
460461
461-
Both [join] and [cancelAndJoin] wait for all the finalization actions to complete, so the example above
462-
produces the following output:
462+
Both [join][Job.join] and [cancelAndJoin] wait for all the finalization actions to complete,
463+
so the example above produces the following output:
463464

464465
```text
465466
I'm sleeping 0 ...
@@ -1047,7 +1048,7 @@ main: Who has survived request cancellation?
10471048
### Parental responsibilities
10481049

10491050
A parent coroutine always waits for completion of all its children. Parent does not have to explicitly track
1050-
all the children it launches and it does not have to use [join] to wait for them at the end:
1051+
all the children it launches and it does not have to use [Job.join] to wait for them at the end:
10511052

10521053
```kotlin
10531054
fun main(args: Array<String>) = runBlocking<Unit> {
@@ -1132,7 +1133,7 @@ and update data, do animations, etc. All of these coroutines must be cancelled w
11321133
to avoid memory leaks.
11331134

11341135
We can manage a lifecycle of our coroutines by creating an instance of [Job] that is tied to
1135-
the lifecycle of our activity. A job instance is created using [`Job()`][Job] factory function
1136+
the lifecycle of our activity. A job instance is created using [Job()] factory function
11361137
as the following example shows. We need to make sure that all the coroutines are started
11371138
with this job in their context and then a single invocation of [Job.cancel] terminates them all.
11381139
Moreover, [Job.join] waits for all of them to complete, so we can also use [cancelAndJoin] here in
@@ -1373,7 +1374,7 @@ The following example prints the first ten prime numbers,
13731374
running the whole pipeline in the context of the main thread. Since all the coroutines are launched as
13741375
children of the main [runBlocking] coroutine in its [coroutineContext][CoroutineScope.coroutineContext],
13751376
we don't have to keep an explicit list of all the coroutine we have created.
1376-
We use [CoroutineContext.cancelChildren] extension to cancel all the children coroutines.
1377+
We use [cancelChildren] extension function to cancel all the children coroutines.
13771378

13781379
```kotlin
13791380
fun main(args: Array<String>) = runBlocking<Unit> {
@@ -1529,7 +1530,7 @@ The channels shown so far had no buffer. Unbuffered channels transfer elements w
15291530
meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
15301531
if receive is invoked first, it is suspended until send is invoked.
15311532

1532-
Both [`Channel()`][Channel] factory function and [produce] builder take an optional `capacity` parameter to
1533+
Both [Channel()] factory function and [produce] builder take an optional `capacity` parameter to
15331534
specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
15341535
similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
15351536

@@ -1829,7 +1830,7 @@ that is never executed concurrently. In a blocking world you'd typically use `sy
18291830
Coroutine's alternative is called [Mutex]. It has [lock][Mutex.lock] and [unlock][Mutex.unlock] functions to
18301831
delimit a critical section. The key difference is that `Mutex.lock` is a suspending function. It does not block a thread.
18311832

1832-
There is also [Mutex.withLock] extension function that conveniently represents
1833+
There is also [withLock] extension function that conveniently represents
18331834
`mutex.lock(); try { ... } finally { mutex.unlock() }` pattern:
18341835

18351836
```kotlin
@@ -2292,6 +2293,8 @@ Channel was closed
22922293
[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html
22932294
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
22942295
[cancelAndJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/cancel-and-join.html
2296+
[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
2297+
[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/join.html
22952298
[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-cancellation-exception.html
22962299
[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/yield.html
22972300
[CoroutineScope.isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/is-active.html
@@ -2311,21 +2314,23 @@ Channel was closed
23112314
[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
23122315
[newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-coroutine-context.html
23132316
[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-name/index.html
2314-
[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
2315-
[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/join.html
2317+
[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job.html
2318+
[cancelChildren]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/kotlin.coroutines.experimental.-coroutine-context/cancel-children.html
23162319
[CompletableDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-completable-deferred/index.html
23172320
[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/on-await.html
23182321
<!--- INDEX kotlinx.coroutines.experimental.sync -->
23192322
[Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/index.html
23202323
[Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/lock.html
23212324
[Mutex.unlock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/unlock.html
2325+
[withLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/with-lock.html
23222326
<!--- INDEX kotlinx.coroutines.experimental.channels -->
23232327
[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html
23242328
[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/send.html
23252329
[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/receive.html
23262330
[SendChannel.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/close.html
23272331
[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/produce.html
23282332
[consumeEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/consume-each.html
2333+
[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel.html
23292334
[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/actor.html
23302335
[ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive.html
23312336
[ReceiveChannel.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive-or-null.html

knit/src/Knit.kt

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const val FLEXIBLE_THREAD_PREDICATE = "FLEXIBLE_THREAD"
6363
const val LINES_START_UNORDERED_PREDICATE = "LINES_START_UNORDERED"
6464
const val LINES_START_PREDICATE = "LINES_START"
6565

66-
val API_REF_REGEX = Regex("(^|[ \\]])\\[([A-Za-z0-9_.]+)\\]($|[^\\[\\(])")
66+
val API_REF_REGEX = Regex("(^|[ \\]])\\[([A-Za-z0-9_().]+)\\]($|[^\\[\\(])")
6767

6868
fun main(args: Array<String>) {
6969
if (args.isEmpty()) {
@@ -424,6 +424,22 @@ val apiIndexCache: MutableMap<ApiIndexKey, Map<String, String>> = HashMap()
424424
val REF_LINE_REGEX = Regex("<a href=\"([a-z/.\\-]+)\">([a-zA-z.]+)</a>")
425425
val INDEX_HTML = "/index.html"
426426
val INDEX_MD = "/index.md"
427+
val FUNCTIONS_SECTION_HEADER = "### Functions"
428+
429+
val AMBIGUOUS = "#AMBIGUOUS: "
430+
431+
fun HashMap<String,String>.putUnambiguous(key: String, value: String) {
432+
val oldValue = this[key]
433+
val putVal =
434+
if (oldValue != null && oldValue != value) {
435+
when {
436+
oldValue.contains("[$value]") -> oldValue
437+
oldValue.startsWith(AMBIGUOUS) -> "$oldValue; [$value]"
438+
else -> "$AMBIGUOUS[$oldValue]; [$value]"
439+
}
440+
} else value
441+
put(key, putVal)
442+
}
427443

428444
fun loadApiIndex(
429445
docsRoot: String,
@@ -434,18 +450,28 @@ fun loadApiIndex(
434450
val fileName = docsRoot + "/" + path + INDEX_MD
435451
val visited = mutableSetOf<String>()
436452
val map = HashMap<String,String>()
453+
var inFunctionsSection = false
437454
File(fileName).withLineNumberReader<LineNumberReader>(::LineNumberReader) {
438455
while (true) {
439456
val line = readLine() ?: break
457+
if (line == FUNCTIONS_SECTION_HEADER) inFunctionsSection = true
440458
val result = REF_LINE_REGEX.matchEntire(line) ?: continue
441-
val refLink = result.groups[1]!!.value
442-
if (refLink.startsWith("..")) continue // ignore cross-references
443-
val refName = namePrefix + result.groups[2]!!.value
444-
map.putIfAbsent(refName, path + "/" + refLink)
445-
map.putIfAbsent(pkg + "." + refName, path + "/" + refLink)
446-
if (refLink.endsWith(INDEX_HTML)) {
447-
if (visited.add(refLink)) {
448-
val path2 = path + "/" + refLink.substring(0, refLink.length - INDEX_HTML.length)
459+
val link = result.groups[1]!!.value
460+
if (link.startsWith("..")) continue // ignore cross-references
461+
val absLink = path + "/" + link
462+
var name = result.groups[2]!!.value
463+
// a special disambiguation fix for pseudo-constructor functions
464+
if (inFunctionsSection && name[0] in 'A'..'Z') name += "()"
465+
val refName = namePrefix + name
466+
val fqName = pkg + "." + refName
467+
// Put short names for extensions on 3rd party classes (prefix is FQname of those classes)
468+
if (namePrefix != "" && namePrefix[0] in 'a'..'z') map.putUnambiguous(name, absLink)
469+
// Always put fully qualified names
470+
map.putUnambiguous(refName, absLink)
471+
map.putUnambiguous(fqName, absLink)
472+
if (link.endsWith(INDEX_HTML)) {
473+
if (visited.add(link)) {
474+
val path2 = path + "/" + link.substring(0, link.length - INDEX_HTML.length)
449475
map += loadApiIndex(docsRoot, path2, pkg, refName + ".")
450476
?: throw IllegalArgumentException("Failed to parse ${docsRoot + "/" + path2}")
451477
}
@@ -473,6 +499,10 @@ fun processApiIndex(
473499
while (it.hasNext()) {
474500
val refName = it.next()
475501
val refLink = map[refName] ?: continue
502+
if (refLink.startsWith(AMBIGUOUS)) {
503+
println("WARNING: Ambiguous reference to [$refName]: ${refLink.substring(AMBIGUOUS.length)}")
504+
continue
505+
}
476506
indexList += "[$refName]: $siteRoot/$refLink"
477507
it.remove()
478508
}

0 commit comments

Comments
 (0)