gdharness 1.1.32 → 1.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli.js +129 -25
- package/build/index.js +123 -20
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -8892,6 +8892,7 @@ function wholeWord(name, flags = "gu") {
|
|
|
8892
8892
|
function occurrencesOf(source, name, regions = regionsOf(source)) {
|
|
8893
8893
|
const found = [];
|
|
8894
8894
|
let index = 0;
|
|
8895
|
+
let code = null;
|
|
8895
8896
|
for (const match of source.matchAll(wholeWord(name))) {
|
|
8896
8897
|
const offset = match.index;
|
|
8897
8898
|
while (index < regions.length - 1 && (regions[index]?.end ?? 0) <= offset) {
|
|
@@ -8901,16 +8902,17 @@ function occurrencesOf(source, name, regions = regionsOf(source)) {
|
|
|
8901
8902
|
let afterDot = false;
|
|
8902
8903
|
let declaredAs = null;
|
|
8903
8904
|
if (kind === "code") {
|
|
8905
|
+
code ??= codeOf(source, regions);
|
|
8904
8906
|
let back = offset - 1;
|
|
8905
|
-
while (back >= 0 && /[\s\\]/.test(
|
|
8907
|
+
while (back >= 0 && /[\s\\]/.test(code[back] ?? "")) {
|
|
8906
8908
|
back -= 1;
|
|
8907
8909
|
}
|
|
8908
|
-
afterDot =
|
|
8910
|
+
afterDot = code[back] === "." && code[back - 1] !== ".";
|
|
8909
8911
|
let wordStart = back + 1;
|
|
8910
|
-
while (wordStart > 0 && isIdentifierPart(
|
|
8912
|
+
while (wordStart > 0 && isIdentifierPart(code[wordStart - 1])) {
|
|
8911
8913
|
wordStart -= 1;
|
|
8912
8914
|
}
|
|
8913
|
-
const word =
|
|
8915
|
+
const word = code.slice(wordStart, back + 1);
|
|
8914
8916
|
declaredAs = DECLARING.has(word) ? word : null;
|
|
8915
8917
|
}
|
|
8916
8918
|
found.push({ offset, kind, afterDot, declaredAs });
|
|
@@ -17756,7 +17758,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17756
17758
|
},
|
|
17757
17759
|
{
|
|
17758
17760
|
name: "script_edit",
|
|
17759
|
-
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none: changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene or
|
|
17761
|
+
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none: changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a find_children string, a word in a comment, a node named like the class, a call on a value whose type the analyser could not tell. Read leftAlone before calling the rename done; nothing in it was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled.",
|
|
17760
17762
|
parameters: {
|
|
17761
17763
|
projectPath: PROJECT_PATH,
|
|
17762
17764
|
scriptPath: SCRIPT_PATH,
|
|
@@ -39654,6 +39656,33 @@ function projectTexts(projectPath) {
|
|
|
39654
39656
|
visit(projectPath, "");
|
|
39655
39657
|
return found;
|
|
39656
39658
|
}
|
|
39659
|
+
function ignoredTexts(projectPath) {
|
|
39660
|
+
const found = [];
|
|
39661
|
+
const visit = (directory, prefix, ignored) => {
|
|
39662
|
+
const under = ignored || steppedOver(directory);
|
|
39663
|
+
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
39664
|
+
if (skipped(entry.name)) {
|
|
39665
|
+
continue;
|
|
39666
|
+
}
|
|
39667
|
+
const absolute = join20(directory, entry.name);
|
|
39668
|
+
const spelled = `${prefix}${entry.name}`;
|
|
39669
|
+
if (entry.isDirectory()) {
|
|
39670
|
+
visit(absolute, `${spelled}/`, under);
|
|
39671
|
+
continue;
|
|
39672
|
+
}
|
|
39673
|
+
const extension = entry.name.includes(".") ? entry.name.split(".").pop()?.toLowerCase() ?? "" : "";
|
|
39674
|
+
if (!under || !entry.isFile() || BINARY_EXTENSIONS.has(extension) || entry.name === ".gdignore") {
|
|
39675
|
+
continue;
|
|
39676
|
+
}
|
|
39677
|
+
const bytes = readFileSync17(absolute);
|
|
39678
|
+
if (!isBinary(bytes)) {
|
|
39679
|
+
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
39680
|
+
}
|
|
39681
|
+
}
|
|
39682
|
+
};
|
|
39683
|
+
visit(projectPath, "", false);
|
|
39684
|
+
return found;
|
|
39685
|
+
}
|
|
39657
39686
|
function searchProject(projectPath, options) {
|
|
39658
39687
|
const extensions = options.fileTypes === undefined ? null : new Set(options.fileTypes.map((ext) => ext.replace(/^\./, "").toLowerCase()).filter(Boolean));
|
|
39659
39688
|
const result = {
|
|
@@ -39901,33 +39930,79 @@ function declaredIn(scripts) {
|
|
|
39901
39930
|
}
|
|
39902
39931
|
return declared;
|
|
39903
39932
|
}
|
|
39933
|
+
function docBlockAt(text, offset) {
|
|
39934
|
+
const lineStartOf = (at) => text.lastIndexOf(`
|
|
39935
|
+
`, at - 1) + 1;
|
|
39936
|
+
const contentOf = (lineStart) => {
|
|
39937
|
+
let at = lineStart;
|
|
39938
|
+
while (text[at] === " " || text[at] === "\t") {
|
|
39939
|
+
at += 1;
|
|
39940
|
+
}
|
|
39941
|
+
return text.startsWith("##", at) ? at + 2 : null;
|
|
39942
|
+
};
|
|
39943
|
+
let top = lineStartOf(offset);
|
|
39944
|
+
if (contentOf(top) === null) {
|
|
39945
|
+
return null;
|
|
39946
|
+
}
|
|
39947
|
+
while (top > 0 && contentOf(lineStartOf(top - 1)) !== null) {
|
|
39948
|
+
top = lineStartOf(top - 1);
|
|
39949
|
+
}
|
|
39950
|
+
let joined = "";
|
|
39951
|
+
const from = [];
|
|
39952
|
+
for (let line = top;; ) {
|
|
39953
|
+
const content = contentOf(line);
|
|
39954
|
+
if (content === null) {
|
|
39955
|
+
break;
|
|
39956
|
+
}
|
|
39957
|
+
const nextBreak = text.indexOf(`
|
|
39958
|
+
`, line);
|
|
39959
|
+
let end = nextBreak < 0 ? text.length : nextBreak;
|
|
39960
|
+
if (text[end - 1] === "\r") {
|
|
39961
|
+
end -= 1;
|
|
39962
|
+
}
|
|
39963
|
+
if (joined.length > 0) {
|
|
39964
|
+
joined += " ";
|
|
39965
|
+
from.push(-1);
|
|
39966
|
+
}
|
|
39967
|
+
for (let at = content;at < end; at += 1) {
|
|
39968
|
+
joined += text[at];
|
|
39969
|
+
from.push(at);
|
|
39970
|
+
}
|
|
39971
|
+
if (nextBreak < 0) {
|
|
39972
|
+
break;
|
|
39973
|
+
}
|
|
39974
|
+
line = nextBreak + 1;
|
|
39975
|
+
}
|
|
39976
|
+
return { joined, from };
|
|
39977
|
+
}
|
|
39904
39978
|
function docLinkAt(text, offset) {
|
|
39905
|
-
const
|
|
39906
|
-
|
|
39907
|
-
|
|
39908
|
-
`, offset);
|
|
39909
|
-
const lineEnd = nextBreak < 0 ? text.length : nextBreak;
|
|
39910
|
-
const open = text.lastIndexOf("[", offset);
|
|
39911
|
-
const close = text.indexOf("]", offset);
|
|
39912
|
-
if (open < lineStart || close === -1 || close > lineEnd) {
|
|
39979
|
+
const block = docBlockAt(text, offset);
|
|
39980
|
+
const at = block?.from.indexOf(offset) ?? -1;
|
|
39981
|
+
if (block === null || at < 0) {
|
|
39913
39982
|
return null;
|
|
39914
39983
|
}
|
|
39915
|
-
const
|
|
39984
|
+
const { joined } = block;
|
|
39985
|
+
const open = joined.lastIndexOf("[", at);
|
|
39986
|
+
const close = joined.indexOf("]", at);
|
|
39987
|
+
if (open < 0 || close < 0) {
|
|
39988
|
+
return null;
|
|
39989
|
+
}
|
|
39990
|
+
const inside = joined.slice(open + 1, close);
|
|
39916
39991
|
if (inside.includes("[") || inside.includes("]")) {
|
|
39917
39992
|
return null;
|
|
39918
39993
|
}
|
|
39919
|
-
const match =
|
|
39994
|
+
const match = /^\s*(?:([a-z_]+)\s+)?([\p{L}_][\p{L}\p{N}_]*(?:\.[\p{L}_][\p{L}\p{N}_]*)*)\s*$/u.exec(inside);
|
|
39920
39995
|
if (match === null || match[1] !== undefined && !DOC_LINK_KINDS.has(match[1])) {
|
|
39921
39996
|
return null;
|
|
39922
39997
|
}
|
|
39923
|
-
const
|
|
39924
|
-
const
|
|
39925
|
-
let
|
|
39998
|
+
const path = match[2] ?? "";
|
|
39999
|
+
const parts = path.split(".");
|
|
40000
|
+
let partAt = open + 1 + inside.trimEnd().length - path.length;
|
|
39926
40001
|
for (const [index, part] of parts.entries()) {
|
|
39927
|
-
if (
|
|
40002
|
+
if (partAt === at) {
|
|
39928
40003
|
return { kind: match[1] ?? null, parts, index };
|
|
39929
40004
|
}
|
|
39930
|
-
|
|
40005
|
+
partAt += part.length + 1;
|
|
39931
40006
|
}
|
|
39932
40007
|
return null;
|
|
39933
40008
|
}
|
|
@@ -40325,6 +40400,33 @@ function planMove(args, plan) {
|
|
|
40325
40400
|
mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
|
|
40326
40401
|
};
|
|
40327
40402
|
}
|
|
40403
|
+
function mentionIgnored(plan, ignored, name, movedFrom) {
|
|
40404
|
+
const mentions = [...plan.mentions];
|
|
40405
|
+
const why = "under a directory holding a .gdignore, which the engine does not load, so it was not changed";
|
|
40406
|
+
for (const file of ignored) {
|
|
40407
|
+
const lines = new Lines(file.text);
|
|
40408
|
+
const offsets = occurrencesOf(file.text, name, [{ kind: "code", start: 0, end: file.text.length }]).map((one) => one.offset);
|
|
40409
|
+
if (movedFrom !== null) {
|
|
40410
|
+
let at = file.text.indexOf(movedFrom);
|
|
40411
|
+
while (at >= 0) {
|
|
40412
|
+
offsets.push(at);
|
|
40413
|
+
at = file.text.indexOf(movedFrom, at + movedFrom.length);
|
|
40414
|
+
}
|
|
40415
|
+
}
|
|
40416
|
+
const seen = new Set;
|
|
40417
|
+
for (const offset of offsets) {
|
|
40418
|
+
const line = lines.positionOf(offset).line + 1;
|
|
40419
|
+
if (!seen.has(line)) {
|
|
40420
|
+
seen.add(line);
|
|
40421
|
+
mentions.push({ file: file.path, line, kind: "ignored", text: lines.lineAt(offset).trim(), why });
|
|
40422
|
+
}
|
|
40423
|
+
}
|
|
40424
|
+
}
|
|
40425
|
+
return {
|
|
40426
|
+
edits: plan.edits,
|
|
40427
|
+
mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
|
|
40428
|
+
};
|
|
40429
|
+
}
|
|
40328
40430
|
function rewritesOf(plan, texts, move) {
|
|
40329
40431
|
const byPath = new Map(texts.map((file) => [file.path, file]));
|
|
40330
40432
|
const byFile = new Map;
|
|
@@ -40637,6 +40739,7 @@ async function renameSymbol(request, services) {
|
|
|
40637
40739
|
exists: (path) => existsSync18(`${projectPath}/${path.slice("res://".length)}`)
|
|
40638
40740
|
}, plan);
|
|
40639
40741
|
}
|
|
40742
|
+
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? null : declaringPath);
|
|
40640
40743
|
const rewrites = rewritesOf(plan, texts, moveTo === null || request.newScriptPath === null ? null : { from: declaringPath, to: moveTo, absoluteTo: request.newScriptPath });
|
|
40641
40744
|
const graph = new ClassGraph(scripts, declared);
|
|
40642
40745
|
const rank = (path) => (declaringFiles.includes(path) ? 0 : 1000) + graph.ancestors(`${path}#`).length;
|
|
@@ -47588,14 +47691,15 @@ formatting. \`script_diagnostics\` and \`script_info\` come from the editor's ow
|
|
|
47588
47691
|
\`project_export\`, \`project_test\`, \`script_edit\`, \`script_info structure\` and
|
|
47589
47692
|
\`editor_classes\` need nothing open: they run a short headless engine and are gone before the
|
|
47590
47693
|
answer is printed. The exception is \`script_edit rename\` of a method, variable, signal or other
|
|
47591
|
-
member, which asks the editor's language server which uses are that class's.
|
|
47694
|
+
member, which asks the editor's language server which uses are that class's. \`project_settings
|
|
47695
|
+
get\` is on that list too, reading as it does like a look at a config file: it starts an engine so
|
|
47696
|
+
that a setting nobody wrote down still answers with the default the engine registers for it.
|
|
47592
47697
|
|
|
47593
47698
|
To rename a class or a member across the project, use \`script_edit rename\` rather than a text
|
|
47594
47699
|
replacement: it changes the uses the engine resolves, doc links and what scenes record, and lists
|
|
47595
|
-
every other occurrence of the word under \`leftAlone\`, a \`find_children\` string
|
|
47596
|
-
comment, for you to read. Pass \`preview\` first on a
|
|
47597
|
-
|
|
47598
|
-
default the engine registers for it.
|
|
47700
|
+
every other occurrence of the word under \`leftAlone\`, a \`find_children\` string, a word in a
|
|
47701
|
+
comment or a file under a \`.gdignore\` directory, for you to read. Pass \`preview\` first on a
|
|
47702
|
+
large rename.
|
|
47599
47703
|
|
|
47600
47704
|
Editing a file while a game is running does not change the running game. \`auto_reload\` is an
|
|
47601
47705
|
editor plugin and reloads into the editor's own process; the game is a separate process holding
|
package/build/index.js
CHANGED
|
@@ -26268,6 +26268,7 @@ function wholeWord(name, flags = "gu") {
|
|
|
26268
26268
|
function occurrencesOf(source, name, regions = regionsOf(source)) {
|
|
26269
26269
|
const found = [];
|
|
26270
26270
|
let index = 0;
|
|
26271
|
+
let code = null;
|
|
26271
26272
|
for (const match of source.matchAll(wholeWord(name))) {
|
|
26272
26273
|
const offset = match.index;
|
|
26273
26274
|
while (index < regions.length - 1 && (regions[index]?.end ?? 0) <= offset) {
|
|
@@ -26277,16 +26278,17 @@ function occurrencesOf(source, name, regions = regionsOf(source)) {
|
|
|
26277
26278
|
let afterDot = false;
|
|
26278
26279
|
let declaredAs = null;
|
|
26279
26280
|
if (kind === "code") {
|
|
26281
|
+
code ??= codeOf(source, regions);
|
|
26280
26282
|
let back = offset - 1;
|
|
26281
|
-
while (back >= 0 && /[\s\\]/.test(
|
|
26283
|
+
while (back >= 0 && /[\s\\]/.test(code[back] ?? "")) {
|
|
26282
26284
|
back -= 1;
|
|
26283
26285
|
}
|
|
26284
|
-
afterDot =
|
|
26286
|
+
afterDot = code[back] === "." && code[back - 1] !== ".";
|
|
26285
26287
|
let wordStart = back + 1;
|
|
26286
|
-
while (wordStart > 0 && isIdentifierPart(
|
|
26288
|
+
while (wordStart > 0 && isIdentifierPart(code[wordStart - 1])) {
|
|
26287
26289
|
wordStart -= 1;
|
|
26288
26290
|
}
|
|
26289
|
-
const word =
|
|
26291
|
+
const word = code.slice(wordStart, back + 1);
|
|
26290
26292
|
declaredAs = DECLARING.has(word) ? word : null;
|
|
26291
26293
|
}
|
|
26292
26294
|
found.push({ offset, kind, afterDot, declaredAs });
|
|
@@ -30405,6 +30407,33 @@ function projectTexts(projectPath) {
|
|
|
30405
30407
|
visit(projectPath, "");
|
|
30406
30408
|
return found;
|
|
30407
30409
|
}
|
|
30410
|
+
function ignoredTexts(projectPath) {
|
|
30411
|
+
const found = [];
|
|
30412
|
+
const visit = (directory, prefix, ignored) => {
|
|
30413
|
+
const under = ignored || steppedOver(directory);
|
|
30414
|
+
for (const entry of readdirSync5(directory, { withFileTypes: true })) {
|
|
30415
|
+
if (skipped(entry.name)) {
|
|
30416
|
+
continue;
|
|
30417
|
+
}
|
|
30418
|
+
const absolute = join15(directory, entry.name);
|
|
30419
|
+
const spelled = `${prefix}${entry.name}`;
|
|
30420
|
+
if (entry.isDirectory()) {
|
|
30421
|
+
visit(absolute, `${spelled}/`, under);
|
|
30422
|
+
continue;
|
|
30423
|
+
}
|
|
30424
|
+
const extension = entry.name.includes(".") ? entry.name.split(".").pop()?.toLowerCase() ?? "" : "";
|
|
30425
|
+
if (!under || !entry.isFile() || BINARY_EXTENSIONS.has(extension) || entry.name === ".gdignore") {
|
|
30426
|
+
continue;
|
|
30427
|
+
}
|
|
30428
|
+
const bytes = readFileSync13(absolute);
|
|
30429
|
+
if (!isBinary(bytes)) {
|
|
30430
|
+
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
30431
|
+
}
|
|
30432
|
+
}
|
|
30433
|
+
};
|
|
30434
|
+
visit(projectPath, "", false);
|
|
30435
|
+
return found;
|
|
30436
|
+
}
|
|
30408
30437
|
function searchProject(projectPath, options) {
|
|
30409
30438
|
const extensions = options.fileTypes === undefined ? null : new Set(options.fileTypes.map((ext) => ext.replace(/^\./, "").toLowerCase()).filter(Boolean));
|
|
30410
30439
|
const result = {
|
|
@@ -30613,33 +30642,79 @@ var DOC_LINK_KINDS = new Set([
|
|
|
30613
30642
|
"annotation",
|
|
30614
30643
|
"theme_item"
|
|
30615
30644
|
]);
|
|
30645
|
+
function docBlockAt(text, offset) {
|
|
30646
|
+
const lineStartOf = (at) => text.lastIndexOf(`
|
|
30647
|
+
`, at - 1) + 1;
|
|
30648
|
+
const contentOf = (lineStart) => {
|
|
30649
|
+
let at = lineStart;
|
|
30650
|
+
while (text[at] === " " || text[at] === "\t") {
|
|
30651
|
+
at += 1;
|
|
30652
|
+
}
|
|
30653
|
+
return text.startsWith("##", at) ? at + 2 : null;
|
|
30654
|
+
};
|
|
30655
|
+
let top = lineStartOf(offset);
|
|
30656
|
+
if (contentOf(top) === null) {
|
|
30657
|
+
return null;
|
|
30658
|
+
}
|
|
30659
|
+
while (top > 0 && contentOf(lineStartOf(top - 1)) !== null) {
|
|
30660
|
+
top = lineStartOf(top - 1);
|
|
30661
|
+
}
|
|
30662
|
+
let joined = "";
|
|
30663
|
+
const from = [];
|
|
30664
|
+
for (let line = top;; ) {
|
|
30665
|
+
const content = contentOf(line);
|
|
30666
|
+
if (content === null) {
|
|
30667
|
+
break;
|
|
30668
|
+
}
|
|
30669
|
+
const nextBreak = text.indexOf(`
|
|
30670
|
+
`, line);
|
|
30671
|
+
let end = nextBreak < 0 ? text.length : nextBreak;
|
|
30672
|
+
if (text[end - 1] === "\r") {
|
|
30673
|
+
end -= 1;
|
|
30674
|
+
}
|
|
30675
|
+
if (joined.length > 0) {
|
|
30676
|
+
joined += " ";
|
|
30677
|
+
from.push(-1);
|
|
30678
|
+
}
|
|
30679
|
+
for (let at = content;at < end; at += 1) {
|
|
30680
|
+
joined += text[at];
|
|
30681
|
+
from.push(at);
|
|
30682
|
+
}
|
|
30683
|
+
if (nextBreak < 0) {
|
|
30684
|
+
break;
|
|
30685
|
+
}
|
|
30686
|
+
line = nextBreak + 1;
|
|
30687
|
+
}
|
|
30688
|
+
return { joined, from };
|
|
30689
|
+
}
|
|
30616
30690
|
function docLinkAt(text, offset) {
|
|
30617
|
-
const
|
|
30618
|
-
|
|
30619
|
-
|
|
30620
|
-
`, offset);
|
|
30621
|
-
const lineEnd = nextBreak < 0 ? text.length : nextBreak;
|
|
30622
|
-
const open = text.lastIndexOf("[", offset);
|
|
30623
|
-
const close = text.indexOf("]", offset);
|
|
30624
|
-
if (open < lineStart || close === -1 || close > lineEnd) {
|
|
30691
|
+
const block = docBlockAt(text, offset);
|
|
30692
|
+
const at = block?.from.indexOf(offset) ?? -1;
|
|
30693
|
+
if (block === null || at < 0) {
|
|
30625
30694
|
return null;
|
|
30626
30695
|
}
|
|
30627
|
-
const
|
|
30696
|
+
const { joined } = block;
|
|
30697
|
+
const open = joined.lastIndexOf("[", at);
|
|
30698
|
+
const close = joined.indexOf("]", at);
|
|
30699
|
+
if (open < 0 || close < 0) {
|
|
30700
|
+
return null;
|
|
30701
|
+
}
|
|
30702
|
+
const inside = joined.slice(open + 1, close);
|
|
30628
30703
|
if (inside.includes("[") || inside.includes("]")) {
|
|
30629
30704
|
return null;
|
|
30630
30705
|
}
|
|
30631
|
-
const match =
|
|
30706
|
+
const match = /^\s*(?:([a-z_]+)\s+)?([\p{L}_][\p{L}\p{N}_]*(?:\.[\p{L}_][\p{L}\p{N}_]*)*)\s*$/u.exec(inside);
|
|
30632
30707
|
if (match === null || match[1] !== undefined && !DOC_LINK_KINDS.has(match[1])) {
|
|
30633
30708
|
return null;
|
|
30634
30709
|
}
|
|
30635
|
-
const
|
|
30636
|
-
const
|
|
30637
|
-
let
|
|
30710
|
+
const path = match[2] ?? "";
|
|
30711
|
+
const parts = path.split(".");
|
|
30712
|
+
let partAt = open + 1 + inside.trimEnd().length - path.length;
|
|
30638
30713
|
for (const [index, part] of parts.entries()) {
|
|
30639
|
-
if (
|
|
30714
|
+
if (partAt === at) {
|
|
30640
30715
|
return { kind: match[1] ?? null, parts, index };
|
|
30641
30716
|
}
|
|
30642
|
-
|
|
30717
|
+
partAt += part.length + 1;
|
|
30643
30718
|
}
|
|
30644
30719
|
return null;
|
|
30645
30720
|
}
|
|
@@ -31046,6 +31121,33 @@ function planMove(args, plan) {
|
|
|
31046
31121
|
mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
|
|
31047
31122
|
};
|
|
31048
31123
|
}
|
|
31124
|
+
function mentionIgnored(plan, ignored, name, movedFrom) {
|
|
31125
|
+
const mentions = [...plan.mentions];
|
|
31126
|
+
const why = "under a directory holding a .gdignore, which the engine does not load, so it was not changed";
|
|
31127
|
+
for (const file of ignored) {
|
|
31128
|
+
const lines = new Lines(file.text);
|
|
31129
|
+
const offsets = occurrencesOf(file.text, name, [{ kind: "code", start: 0, end: file.text.length }]).map((one) => one.offset);
|
|
31130
|
+
if (movedFrom !== null) {
|
|
31131
|
+
let at = file.text.indexOf(movedFrom);
|
|
31132
|
+
while (at >= 0) {
|
|
31133
|
+
offsets.push(at);
|
|
31134
|
+
at = file.text.indexOf(movedFrom, at + movedFrom.length);
|
|
31135
|
+
}
|
|
31136
|
+
}
|
|
31137
|
+
const seen = new Set;
|
|
31138
|
+
for (const offset of offsets) {
|
|
31139
|
+
const line = lines.positionOf(offset).line + 1;
|
|
31140
|
+
if (!seen.has(line)) {
|
|
31141
|
+
seen.add(line);
|
|
31142
|
+
mentions.push({ file: file.path, line, kind: "ignored", text: lines.lineAt(offset).trim(), why });
|
|
31143
|
+
}
|
|
31144
|
+
}
|
|
31145
|
+
}
|
|
31146
|
+
return {
|
|
31147
|
+
edits: plan.edits,
|
|
31148
|
+
mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
|
|
31149
|
+
};
|
|
31150
|
+
}
|
|
31049
31151
|
function rewritesOf(plan, texts, move) {
|
|
31050
31152
|
const byPath = new Map(texts.map((file) => [file.path, file]));
|
|
31051
31153
|
const byFile = new Map;
|
|
@@ -31603,6 +31705,7 @@ async function renameSymbol(request, services) {
|
|
|
31603
31705
|
exists: (path) => existsSync14(`${projectPath}/${path.slice("res://".length)}`)
|
|
31604
31706
|
}, plan);
|
|
31605
31707
|
}
|
|
31708
|
+
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? null : declaringPath);
|
|
31606
31709
|
const rewrites = rewritesOf(plan, texts, moveTo === null || request.newScriptPath === null ? null : { from: declaringPath, to: moveTo, absoluteTo: request.newScriptPath });
|
|
31607
31710
|
const graph = new ClassGraph(scripts, declared);
|
|
31608
31711
|
const rank = (path) => (declaringFiles.includes(path) ? 0 : 1000) + graph.ancestors(`${path}#`).length;
|
|
@@ -32899,7 +33002,7 @@ var TOOL_SPECS = [
|
|
|
32899
33002
|
},
|
|
32900
33003
|
{
|
|
32901
33004
|
name: "script_edit",
|
|
32902
|
-
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none: changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene or
|
|
33005
|
+
description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none: changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a find_children string, a word in a comment, a node named like the class, a call on a value whose type the analyser could not tell. Read leftAlone before calling the rename done; nothing in it was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled.",
|
|
32903
33006
|
parameters: {
|
|
32904
33007
|
projectPath: PROJECT_PATH,
|
|
32905
33008
|
scriptPath: SCRIPT_PATH,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.33",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|