///|
fn LspServer::resource_references(self : LspServer) -> Json raise {
let rows : Array[Json] = []
let names = self.documents.keys().collect()
names.sort()
for uri in names {
let document = self.documents[uri]
if !lsp_is_kv3(uri, document.text) {
continue
}
let source = parse_kv3_preserving(document.text) catch { _ => continue }
for reference in source.resources(roots=self.resource_roots) {
if rows.length() >= 10000 {
raise Failure("Resource workspace exceeds 10000 references")
}
let target = reference.target.map(path => lsp_file_uri(path))
rows.push(
Json::object({
"uri": Json::string(uri),
"range": lsp_range(document.text, reference.start, reference.end),
"resource": Json::string(reference.resource),
"target": match target {
Some(t) => Json::string(t)
None => Json::null()
},
"status": Json::string(
match reference.target {
Some(path) =>
self.resource_states.get(path).unwrap_or("unchecked")
None => reference.status
},
),
}),
)
}
}
Json::array(rows)
}
///|
fn LspServer::resource_targets(self : LspServer) -> Json raise {
let targets : Map[String, Bool] = Map([])
guard self.resource_references() is Array(rows) else {
return Json::array([])
}
for row in rows {
if row is Object(fields) && fields.get("target") is Some(String(target)) {
targets[target] = true
}
}
let names = targets.keys().collect()
names.sort()
Json::array(names.map(s => Json::string(s)))
}
///|
fn LspServer::resource_diagnostics(
self : LspServer,
uri : String,
) -> Array[Json] raise {
let document = self.documents[uri]
let source = parse_kv3_preserving(document.text)
let rows : Array[Json] = []
for reference in source.resources(roots=self.resource_roots) {
let state = match reference.target {
Some(path) => self.resource_states.get(path).unwrap_or("unchecked")
None => reference.status
}
if state != "missing" && state != "invalid" {
continue
}
rows.push(
Json::object({
"range": lsp_range(document.text, reference.start, reference.end),
"severity": Json::number(2),
"code": Json::string(
if state == "missing" {
"missing_resource"
} else {
"invalid_resource_path"
},
),
"source": Json::string("MoonValve"),
"message": Json::string(
if state == "missing" {
"Resource file confirmed missing: " + reference.resource
} else {
"Resource path must be a normalized relative file path: " +
reference.resource
},
),
}),
)
if rows.length() >= 128 {
break
}
}
rows
}
///|
fn LspServer::resource_links(
self : LspServer,
uri : String,
offset : Int32?,
) -> Json raise {
let document = self.documents[uri]
let source = parse_kv3_preserving(document.text)
let rows : Array[Json] = []
for reference in source.resources(roots=self.resource_roots) {
guard reference.target is Some(target) else { continue }
if self.resource_states.get(target) != Some("present") {
continue
}
if offset is Some(at) {
if at >= reference.start && at < reference.end {
rows.push(
Json::object({
"uri": Json::string(lsp_file_uri(target)),
"range": lsp_range("", 0, 0),
}),
)
}
} else {
rows.push(
Json::object({
"target": Json::string(lsp_file_uri(target)),
"range": lsp_range(document.text, reference.start, reference.end),
}),
)
}
}
Json::array(rows)
}
///|
fn LspServer::resource_rename_edits(
self : LspServer,
moves : Array[(String, String)],
) -> Array[Json] raise {
if self.resource_roots.is_empty() {
return []
}
let relevant = moves.filter(pair => {
let (from, to) = pair
self.resource_roots.any(root => {
from.has_prefix(root.directory + "/") ||
to.has_prefix(root.directory + "/") ||
from == root.directory ||
root.directory.has_prefix(from + "/")
})
})
if relevant.is_empty() {
return []
}
// Changing a configured root itself requires an explicit setting update.
for (from, _) in relevant {
if self.resource_roots.any(root => {
root.directory == from || root.directory.has_prefix(from + "/")
}) {
raise Failure(
"Moving a configured resource root requires updating resourceRoots first",
)
}
}
let moves : Map[String, String] = Map([])
for (from, to) in relevant {
moves[from] = to
}
let edits : Array[Json] = []
for uri, document in self.documents {
if !lsp_is_kv3(uri, document.text) {
continue
}
let source = parse_kv3_preserving(document.text) catch {
_ =>
raise Failure(
"Cannot update resource references in malformed KV3: " + uri,
)
}
let result = source.rewrite_resources(self.resource_roots, moves)
if result.text() == document.text {
continue
}
edits.push(
Json::object({
"textDocument": Json::object({
"uri": Json::string(uri),
"version": if document.opened {
Json::number(document.version.to_double())
} else {
Json::null()
},
}),
"edits": Json::array([
Json::object({
"range": lsp_range(document.text, 0, document.text.char_length()),
"newText": Json::string(result.text()),
}),
]),
}),
)
}
edits
}