# \[\`foo\`\](@ref) to auto-link the Julia manual on discourse?

**URL:** <https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055>\
**Category:** Meta Discussion\
**Created:** [December 2, 2023, 7:24pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055 "2023-12-02T19:24:07Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 2, 2023, 7:24pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/1 "2023-12-02T19:24:07Z")

</div>

I find myself linking to the Julia manual a lot when answering questions on Discourse, and it would be nice to make that more convenient.

Is there any chance of supporting Documenter.jl style `[`foo`](@ref)` links to the Julia manual?

---

<div class="post-metadata">

**Author:** ![tamasgal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamasgal/32/27946_2.png) [@tamasgal](https://discourse.julialang.org/u/tamasgal)\
**Post date:** [December 2, 2023, 7:37pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/2 "2023-12-02T19:37:50Z")

</div>

But which version of the docs? 😉

(I often stumble across Git(Lab) issues which link to lines in the source code and people who posted them forgot/ignored that there are “permalinks” to make them valid forever. Otherwise those links can become obsolete or even misleading very quickly)

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [December 6, 2023, 6:11pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/3 "2023-12-06T18:11:20Z")

</div>

I don’t think this is possible. The tools in our toolbox here are pretty limited, and I think Documenter’s `@ref` needs something fairly advanced.

There are really only two tools we have:

- We have the [Auto linkify words](https://discourse.julialang.org/t/automatic-package-links/106275/4) theme component that simply adds a link underneath text that you wrote — like ModelingToolkit.jl — without needing to explicitly write out the `[](...)` markdown. But that doesn’t _change_ the text that appears, it just adds a link to it. You can use regexes there.

- We also have the builtin “Replace” functionality from [“Watched Words”](https://meta.discourse.org/t/watched-words-reference-guide/241735), which can actually replace text that’s written, but as our site is currently hosted it doesn’t even support regexes or matches. It’s just a straight-up plain-text find/replace.

But then there’s the bigger question about packages: How could I know how to link to [`CSV.read`](https://csv.juliadata.org/stable/reading.html#CSV.read) or [`Random.rand!`](https://docs.julialang.org/en/v1/stdlib/Random/#Random.rand!)? Perhaps there’s a missing Documenter.jl (and maybe DocumentationGenerator.jl) feature here: provide a URL endpoint like `example.com/base/path/to/docs/stable/api/Module.function` that will redirect to the place where that docstring lives.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [December 6, 2023, 6:45pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/4 "2023-12-06T18:45:21Z")

</div>

How about a bot? Could we have an automated user that would reply with links to the documentation?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [December 6, 2023, 6:56pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/5 "2023-12-06T18:56:47Z")

</div>

That sounds very noisy. We could have a @doc user with sufficient privileges to edit others’ posts… in fact the @system user already edits posts in some contexts (see this post’s very edit history).

But the general problem remains, how do you know _what to do_? How do you know `Base.rand` lives at `stdlib/Random/#Base.rand` while `Base.zeros` is `base/arrays/#Base.zeros`? Or that the `CSV.read` docstring is on `stable/reading.html#CSV.read` while `CSV.write` is at `stable/writing.html#CSV.write`…

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [December 6, 2023, 7:49pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/6 "2023-12-06T19:49:49Z")

</div>

I might be misunderstanding the question. I thought this information is encoded in a JSON “database” somewhere such as [https://docs.julialang.org/en/v1/search\_index.js](https://docs.julialang.org/en/v1/search_index.js)

```json
{
  "location": "base/arrays/#Base.zeros",
  "page": "Arrays",
  "title": "Base.zeros",
  "text": "zeros([T=Float64,] dims::Tuple)\nzeros([T=Float64,] dims...)\n\nCreate an Array, with element type T, of all zeros with size specified by dims. See also fill, ones, zero.\n\nExamples\n\njulia> zeros(1)\n1-element Vector{Float64}:\n 0.0\n\njulia> zeros(Int8, 2, 3)\n2×3 Matrix{Int8}:\n 0 0 0\n 0 0 0\n\n\n\n\n\n",
  "category": "function"
}

```

Or for CSV, [https://docs.juliahub.com/General/CSV/stable/search\_index.js:](https://docs.juliahub.com/General/CSV/stable/search_index.js:)

```json
{
  "location": "writing.html#CSV.write",
  "page": "Writing",
  "title": "CSV.write",
  "text": "CSV.write(file, table; kwargs...) => file\ntable |> CSV.write(file; kwargs...) => file\n\nWrite a Tables.jl interface input to a csv file, given as an IO argument or String/FilePaths.jl type representing the file name to write to. Alternatively, CSV.RowWriter creates a row iterator, producing a csv-formatted string for each row in an input table.\n\nSupported keyword arguments include:\n\nbufsize::Int=2^22: The length of the buffer to use when writing each csv-formatted row; default 4MB; if a row is larger than the bufsize an error is thrown\ndelim::Union{Char, String}=',': a character or string to print out as the file's delimiter\nquotechar::Char='\"': ascii character to use for quoting text fields that may contain delimiters or newlines\nopenquotechar::Char: instead of quotechar, use openquotechar and closequotechar to support different starting and ending quote characters\nescapechar::Char='\"': ascii character used to escape quote characters in a text field\nmissingstring::String=\"\": string to print for missing values\ndateformat=Dates.default_format(T): the date format string to use for printing out Date & DateTime columns\nappend=false: whether to append writing to an existing file/IO, if true, it will not write column names by default\ncompress=false: compress the written output using standard gzip compression (provided by the CodecZlib.jl package); note that a compression stream can always be provided as the first \"file\" argument to support other forms of compression; passing compress=true is just for convenience to avoid needing to manually setup a GzipCompressorStream\nwriteheader=!append: whether to write an initial row of delimited column names, not written by default if appending\nheader: pass a list of column names (Symbols or Strings) to use instead of the column names of the input table\nnewline='\\n': character or string to use to separate rows (lines in the csv file)\nquotestrings=false: whether to force all strings to be quoted or not\ndecimal='.': character to use as the decimal point when writing floating point numbers\ntransform=(col,val)->val: a function that is applied to every cell e.g. we can transform all nothing values to missing using (col, val) -> something(val, missing)\nbom=false: whether to write a UTF-8 BOM header (0xEF 0xBB 0xBF) or not\npartition::Bool=false: by passing true, the table argument is expected to implement Tables.partitions and the file argument can either be an indexable collection of IO, file Strings, or a single file String that will have an index appended to the name\n\nExamples\n\nusing CSV, Tables, DataFrames\n\n# write out a DataFrame to csv file\ndf = DataFrame(rand(10, 10), :auto)\nCSV.write(\"data.csv\", df)\n\n# write a matrix to an in-memory IOBuffer\nio = IOBuffer()\nmat = rand(10, 10)\nCSV.write(io, Tables.table(mat))\n\n\n\n\n\n",
  "category": "function"
}

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [December 6, 2023, 8:00pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/7 "2023-12-06T20:00:59Z")

</div>

Ah, perfect, that is exactly the answer to my question there! It’s still something that’d require near-turing-completeness and a bot — it couldn’t be implemented with regexmatches, for example.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [December 6, 2023, 8:21pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/8 "2023-12-06T20:21:25Z")

</div>

Here is some code to lookup the locations.

```julia
using HTTP, JSON3

function get_function_search_index(url::AbstractString="https://docs.julialang.org/en/v1/search_index.js")
    search_index = String(HTTP.get(url).body)
    search_index_json = JSON3.read(@view(search_index[29:end]))
    functions = filter(x->x.category == "function", search_index_json.docs)
    return functions
end

const julia_idx = get_function_search_index()

function find_function_location(title::AbstractString, idx::Vector{JSON3.Object} = julia_idx)
    only(filter(x->x.title==title, idx))
end

function get_function_url(
    title::AbstractString,
    idx::Vector{JSON3.Object} = julia_idx,
    prefix::AbstractString = "https://docs.julialang.org/en/v1/"
)
    return prefix * find_function_location(title, idx)
end

```

Here is a demonstration:

```julia-repl
julia> find_function_location("Base.zeros", idx)
"base/arrays/#Base.zeros"

julia> find_function_location("Base.ones", idx)
"base/arrays/#Base.ones"

julia> find_function_location("Base.println", idx)
"base/io-network/#Base.println"

julia> get_function_url("Base.println")
"https://docs.julialang.org/en/v1/base/io-network/#Base.println"

```

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [December 6, 2023, 11:14pm UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/9 "2023-12-06T23:14:37Z")

</div>

Indeed, Documenter should generate a downloadable index of docstrings: [At-ref proposal with InterSphinx compatibility · Issue #2366 · JuliaDocs/Documenter.jl · GitHub](https://github.com/JuliaDocs/Documenter.jl/issues/2366)

With the limitations of the Discourse site that you describe, I’m not sure how far that would get you, but it would be a first step.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [January 7, 2024, 7:43am UTC](https://discourse.julialang.org/t/foo-ref-to-auto-link-the-julia-manual-on-discourse/107055/10 "2024-01-07T07:43:38Z")

</div>

There is now an inventory file for the Julia 1.10 documentation at [Inventory File Repository · JuliaDocs/DocumenterInterLinks.jl Wiki · GitHub](https://github.com/JuliaDocs/DocumenterInterLinks.jl/wiki/Inventory-File-Repository)

It can be used programmatically (or explored in the REPL) via the [`DocInventories` package](https://github.com/JuliaDocs/DocInventories.jl) – or just with a [TOML parser](https://juliadocs.org/DocInventories.jl/stable/formats/#TOML-Format).
