Files
cell/editors/vscode/lsp/hover.cm
2026-02-09 18:53:13 -06:00

462 lines
14 KiB
Plaintext

// Hover provider for the ƿit LSP.
// Shows documentation for intrinsic functions and variable info.
// Intrinsic function documentation database.
// Each entry: {signature, description}
def intrinsic_docs = {
abs: {
signature: "abs(number)",
description: "Absolute value. Returns null for non-numbers."
},
apply: {
signature: "apply(function, array)",
description: "Execute the function, passing array elements as input values."
},
array: {
signature: "array(value, ...)",
description: "Create arrays. Polymorphic: array(number) creates sized array, array(array) copies, array(array, fn) maps, array(text) splits into characters, array(text, sep) splits by separator."
},
ceiling: {
signature: "ceiling(number, place)",
description: "Round up. If place is 0 or null, round to smallest integer >= number."
},
character: {
signature: "character(value)",
description: "If text, returns the first character. If a non-negative integer, returns the character from that codepoint."
},
codepoint: {
signature: "codepoint(text)",
description: "Returns the codepoint number of the first character."
},
ends_with: {
signature: "ends_with(text, suffix)",
description: "Returns true if the text ends with the given suffix."
},
every: {
signature: "every(array, function)",
description: "Returns true if every element satisfies the predicate."
},
extract: {
signature: "extract(text, pattern, from, to)",
description: "Match text to pattern. Returns a record of saved fields, or null if no match."
},
fallback: {
signature: "fallback(requestor_array)",
description: "Returns a requestor that tries each requestor in order until one succeeds."
},
filter: {
signature: "filter(array, function)",
description: "Returns a new array containing elements for which function returns true."
},
find: {
signature: "find(array, function, reverse, from)",
description: "Returns the element number where function returns true, or null if not found. If second arg is not a function, compares directly."
},
floor: {
signature: "floor(number, place)",
description: "Round down. If place is 0 or null, round to greatest integer <= number."
},
format: {
signature: "format(text, collection, transformer)",
description: "Substitute {key} placeholders in text with values from a collection (array or record)."
},
fraction: {
signature: "fraction(number)",
description: "Returns the fractional part of a number."
},
is_array: {
signature: "is_array(value)",
description: "Returns true if the value is an array."
},
is_blob: {
signature: "is_blob(value)",
description: "Returns true if the value is a blob."
},
is_character: {
signature: "is_character(value)",
description: "Returns true if the value is a single character."
},
is_data: {
signature: "is_data(value)",
description: "Returns true if the value is data (not a function)."
},
is_digit: {
signature: "is_digit(value)",
description: "Returns true if the value is a digit character."
},
is_false: {
signature: "is_false(value)",
description: "Returns true if the value is false."
},
is_fit: {
signature: "is_fit(value)",
description: "Returns true if the value is a fit integer."
},
is_function: {
signature: "is_function(value)",
description: "Returns true if the value is a function."
},
is_integer: {
signature: "is_integer(value)",
description: "Returns true if the value is an integer."
},
is_letter: {
signature: "is_letter(value)",
description: "Returns true if the value is a letter character."
},
is_logical: {
signature: "is_logical(value)",
description: "Returns true if the value is a logical (boolean)."
},
is_lower: {
signature: "is_lower(value)",
description: "Returns true if the value is a lowercase character."
},
is_null: {
signature: "is_null(value)",
description: "Returns true if the value is null."
},
is_number: {
signature: "is_number(value)",
description: "Returns true if the value is a number."
},
is_object: {
signature: "is_object(value)",
description: "Returns true if the value is an object (record)."
},
is_pattern: {
signature: "is_pattern(value)",
description: "Returns true if the value is a pattern (regex)."
},
is_stone: {
signature: "is_stone(value)",
description: "Returns true if the value is frozen (stoned)."
},
is_text: {
signature: "is_text(value)",
description: "Returns true if the value is text."
},
is_true: {
signature: "is_true(value)",
description: "Returns true if the value is true."
},
is_upper: {
signature: "is_upper(value)",
description: "Returns true if the value is an uppercase character."
},
is_whitespace: {
signature: "is_whitespace(value)",
description: "Returns true if the value is a whitespace character."
},
length: {
signature: "length(value)",
description: "Array: number of elements. Text: number of codepoints. Function: arity. Blob: number of bits. Record: record.length()."
},
logical: {
signature: "logical(value)",
description: "Convert to logical. 0/false/null/\"false\" produce false; 1/true/\"true\" produce true."
},
lower: {
signature: "lower(text)",
description: "Returns text with all uppercase characters converted to lowercase."
},
max: {
signature: "max(number, number)",
description: "Returns the larger of two numbers."
},
min: {
signature: "min(number, number)",
description: "Returns the smaller of two numbers."
},
modulo: {
signature: "modulo(dividend, divisor)",
description: "Result has the sign of the divisor."
},
neg: {
signature: "neg(number)",
description: "Negate. Reverse the sign of a number."
},
normalize: {
signature: "normalize(text)",
description: "Unicode normalize."
},
not: {
signature: "not(logical)",
description: "Returns the opposite logical. Returns null for non-logicals."
},
number: {
signature: "number(value, radix_or_format)",
description: "Convert to number. Polymorphic: number(logical), number(text), number(text, radix), number(text, format)."
},
parallel: {
signature: "parallel(requestor_array, throttle, need)",
description: "Start all requestors concurrently. Optional throttle limits concurrency; optional need specifies minimum successes."
},
print: {
signature: "print(value)",
description: "Print a value to standard output."
},
race: {
signature: "race(requestor_array, throttle, need)",
description: "Like parallel but returns as soon as needed results are obtained. Default need is 1."
},
record: {
signature: "record(value, ...)",
description: "Create records. Polymorphic: record(record) copies, record(record, record) merges, record(array) creates from keys."
},
reduce: {
signature: "reduce(array, function, initial, reverse)",
description: "Reduce an array to a single value by applying a function to pairs of elements."
},
remainder: {
signature: "remainder(dividend, divisor)",
description: "For fit integers: dividend - ((dividend // divisor) * divisor)."
},
replace: {
signature: "replace(text, target, replacement, limit)",
description: "Return text with target replaced. Target can be text or pattern. Replacement can be text or function."
},
reverse: {
signature: "reverse(array)",
description: "Returns a new array with elements in the opposite order."
},
round: {
signature: "round(number, place)",
description: "Round to nearest."
},
search: {
signature: "search(text, target, from)",
description: "Search text for target. Returns character position or null."
},
sequence: {
signature: "sequence(requestor_array)",
description: "Process requestors in order. Each result becomes input to the next."
},
sign: {
signature: "sign(number)",
description: "Returns -1, 0, or 1."
},
some: {
signature: "some(array, function)",
description: "Returns true if any element satisfies the predicate."
},
sort: {
signature: "sort(array, select)",
description: "Returns a new sorted array. Sort keys must be all numbers or all texts. Ascending and stable."
},
starts_with: {
signature: "starts_with(text, prefix)",
description: "Returns true if the text starts with the given prefix."
},
stone: {
signature: "stone(value)",
description: "Petrify the value, making it permanently immutable. Deep freeze."
},
text: {
signature: "text(value, ...)",
description: "Convert to text. Polymorphic: text(array, sep) joins, text(number, radix/format) formats, text(text, from, to) substrings."
},
trim: {
signature: "trim(text, reject)",
description: "Remove characters from both ends. Default removes whitespace."
},
trunc: {
signature: "trunc(number, place)",
description: "Truncate toward zero."
},
upper: {
signature: "upper(text)",
description: "Returns text with all lowercase characters converted to uppercase."
},
whole: {
signature: "whole(number)",
description: "Returns the whole part of a number."
},
meme: {
signature: "meme()",
description: "Create a new meme (prototype chain marker)."
},
proto: {
signature: "proto(object, meme)",
description: "Set the prototype meme of an object."
},
isa: {
signature: "isa(object, meme)",
description: "Returns true if the object has the given meme in its prototype chain."
},
splat: {
signature: "splat(function, array)",
description: "Call function with array elements as separate arguments."
},
use: {
signature: "use(path)",
description: "Load a module. Returns the module's exported value. Modules are cached and frozen."
},
pi: {
signature: "pi",
description: "An approximation of circumference / diameter: 3.1415926535897932."
}
}
// Actor intrinsic documentation
def actor_docs = {
"$me": {
signature: "$me",
description: "The address of this actor."
},
"$send": {
signature: "$send(address, message)",
description: "Send a message to another actor."
},
"$start": {
signature: "$start(script, env)",
description: "Start a new actor from a script path."
},
"$stop": {
signature: "$stop()",
description: "Stop this actor."
},
"$delay": {
signature: "$delay(milliseconds)",
description: "Delay processing for a number of milliseconds."
},
"$receiver": {
signature: "$receiver(function)",
description: "Set the message receiver function for this actor."
},
"$clock": {
signature: "$clock(interval, message)",
description: "Send a message to self at regular intervals."
},
"$portal": {
signature: "$portal(name)",
description: "Create a named portal for inter-actor communication."
},
"$contact": {
signature: "$contact(portal_name)",
description: "Connect to a named portal."
},
"$couple": {
signature: "$couple(address)",
description: "Couple with another actor for lifecycle management."
},
"$unneeded": {
signature: "$unneeded(function)",
description: "Set a function to be called when this actor is no longer needed."
},
"$connection": {
signature: "$connection(address)",
description: "Establish a connection with another actor."
},
"$time_limit": {
signature: "$time_limit(milliseconds)",
description: "Set a time limit for this actor's execution."
}
}
// Provide hover info for a token.
var hover = function(doc, line, col, token_at) {
var tok = token_at(doc, line, col)
var info = null
var name = null
var _i = 0
var _j = 0
var scope = null
var v = null
if (tok == null) {
return null
}
// Check intrinsic functions
if (tok.kind == "name" && tok.value != null) {
name = tok.value
info = intrinsic_docs[name]
if (info != null) {
return {
contents: {
kind: "markdown",
value: `**${info.signature}**\n\n${info.description}`
}
}
}
}
// Check actor intrinsics ($name)
if (tok.value != null && starts_with(tok.value, "$")) {
info = actor_docs[tok.value]
if (info != null) {
return {
contents: {
kind: "markdown",
value: `**${info.signature}**\n\n${info.description}`
}
}
}
}
// Check keywords
if (tok.kind == "var" || tok.kind == "def") {
return {
contents: {
kind: "markdown",
value: (tok.kind == "var")
? "**var** — Declare a mutable variable."
: "**def** — Declare a constant."
}
}
}
if (tok.kind == "disrupt") {
return {
contents: {
kind: "markdown",
value: "**disrupt** — Raise an error. Use with **disruption** block to handle errors."
}
}
}
if (tok.kind == "disruption") {
return {
contents: {
kind: "markdown",
value: "**disruption** — Error handling block. Catches errors raised by **disrupt**."
}
}
}
// User variable: show declaration info from scope
if (tok.kind == "name" && tok.value != null && doc.ast != null && doc.ast.scopes != null) {
_i = 0
while (_i < length(doc.ast.scopes)) {
scope = doc.ast.scopes[_i]
if (scope.vars != null) {
_j = 0
while (_j < length(scope.vars)) {
v = scope.vars[_j]
if (v.name == tok.value) {
return {
contents: {
kind: "markdown",
value: (v.is_const == true)
? `**def** ${v.name}`
: `**var** ${v.name}`
}
}
}
_j = _j + 1
}
}
_i = _i + 1
}
}
return null
}
return {
hover: hover,
intrinsic_docs: intrinsic_docs,
actor_docs: actor_docs
}