Archived
275 lines
17 KiB
HTML
275 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Script Command Panel | HiAPI-C# 2025 </title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="title" content="Script Command Panel | HiAPI-C# 2025 ">
|
|
|
|
|
|
<link rel="icon" href="../../../img/HiAPI.favicon.ico">
|
|
<link rel="stylesheet" href="../../../public/docfx.min.css">
|
|
<link rel="stylesheet" href="../../../public/main.css">
|
|
<meta name="docfx:navrel" content="../../../toc.html">
|
|
<meta name="docfx:tocrel" content="toc.html">
|
|
|
|
<meta name="docfx:rel" content="../../../">
|
|
|
|
|
|
|
|
<meta name="loc:inThisArticle" content="In this article">
|
|
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
|
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
|
<meta name="loc:tocFilter" content="Filter by title">
|
|
<meta name="loc:nextArticle" content="Next">
|
|
<meta name="loc:prevArticle" content="Previous">
|
|
<meta name="loc:themeLight" content="Light">
|
|
<meta name="loc:themeDark" content="Dark">
|
|
<meta name="loc:themeAuto" content="Auto">
|
|
<meta name="loc:changeTheme" content="Change theme">
|
|
<meta name="loc:copy" content="Copy">
|
|
<meta name="loc:downloadPdf" content="Download PDF">
|
|
|
|
<script type="module" src="./../../../public/docfx.min.js"></script>
|
|
|
|
<script>
|
|
const theme = localStorage.getItem('theme') || 'auto'
|
|
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
|
<header class="bg-body border-bottom">
|
|
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
|
<div class="container-xxl flex-nowrap">
|
|
<a class="navbar-brand" href="../../../index.html">
|
|
<img id="logo" class="svg" src="../../../img/HiAPI.logo.png" alt="">
|
|
|
|
</a>
|
|
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
|
<i class="bi bi-three-dots"></i>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navpanel">
|
|
<div id="navbar">
|
|
<form class="search" role="search" id="search">
|
|
<i class="bi bi-search"></i>
|
|
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main class="container-xxl">
|
|
<div class="toc-offcanvas">
|
|
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<nav class="toc" id="toc"></nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<div class="actionbar">
|
|
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
|
<i class="bi bi-list"></i>
|
|
</button>
|
|
|
|
<nav id="breadcrumb"></nav>
|
|
</div>
|
|
|
|
<article data-uid="Anatomy-ScriptCommandPanel">
|
|
<h1 id="script-command-panel">Script Command Panel</h1>
|
|
|
|
<p>The key model is <a class="xref" href="../../../api/Hi.SessionCommands.ScriptCommand.html">ScriptCommand</a>.</p>
|
|
<p>The command holds two values: <a class="xref" href="../../../api/Hi.SessionCommands.ScriptCommand.html#Hi_SessionCommands_ScriptCommand_ScriptText">ScriptText</a>, a C# script, and
|
|
<a class="xref" href="../../../api/Hi.SessionCommands.ScriptCommand.html#Hi_SessionCommands_ScriptCommand_ScriptTitle">ScriptTitle</a>, the name it runs under. Both are written into
|
|
the project file, so the script travels with the project. <code>Run</code> evaluates the text against the
|
|
session shell as the globals object, and when the script returns a sequence of actions that sequence
|
|
is yielded into the run.</p>
|
|
<p>The title is what the mission row and the tree node show: the label is composed as <code>Script [title]</code>,
|
|
falling back to a bare <code>Script</code> while the title is empty. A newly added command starts empty on both
|
|
clients — no title, no text.</p>
|
|
<p>The panel renders on the command's own node in the Mission branch of the Execution page's Control
|
|
Tree, below the move / duplicate / delete control bar. A single-purpose kind like this one embeds its
|
|
whole editor on that node rather than growing section child nodes. Its tree checkbox only decides
|
|
whether the run plays the command; a disabled script is skipped during play and its editor stays
|
|
fully usable.</p>
|
|
<h2 id="layout">Layout</h2>
|
|
<ul>
|
|
<li>Head Line
|
|
<ul>
|
|
<li>Script Title Text Field
|
|
<ul>
|
|
<li>The model is <a class="xref" href="../../../api/Hi.SessionCommands.ScriptCommand.html#Hi_SessionCommands_ScriptCommand_ScriptTitle">ScriptTitle</a>.</li>
|
|
<li>Labelled “Title (optional)” on the web, “Script Title” on WPF.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Autosave Indicator (web)
|
|
<ul>
|
|
<li>Shares the title row. See <a href="#saving">Saving</a>.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>Script Editor Area
|
|
<ul>
|
|
<li>The model is <a class="xref" href="../../../api/Hi.SessionCommands.ScriptCommand.html#Hi_SessionCommands_ScriptCommand_ScriptText">ScriptText</a>.</li>
|
|
<li>Fills the rest of the panel.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2 id="the-editor">The Editor</h2>
|
|
<p>The web editor is CodeMirror 6 running the <code>mission-script</code> mode: a stream tokenizer written for
|
|
the dialect a mission script actually is — top-level statements, not a compilation unit. It colours
|
|
keywords and boolean literals, strings (plain, verbatim <code>@""</code>, interpolated <code>$""</code> and <code>$@""</code>),
|
|
character literals, hex and floating-point numbers, line and block comments, and it tags a call site
|
|
apart from a plain identifier. Because it is linear rather than a parser, every identifier of the
|
|
same kind gets the same colour no matter where it sits in the file.</p>
|
|
<p>The C# Lezer grammar the client also ships is not what this editor runs: its <code>compilationUnit</code> rule
|
|
rejects top-level statements, so it would recover from an error on line 1 and tag identical names
|
|
inconsistently. That grammar serves the separate <code>csharp</code> mode a <code>.cs</code> file opens in elsewhere in
|
|
the app.</p>
|
|
<p>Nothing in the highlighting is semantic. Everything the editor knows about types and members comes
|
|
from the backend, through completion.</p>
|
|
<h2 id="completion">Completion</h2>
|
|
<p>Typing an identifier — or asking explicitly — sends the whole script text plus the zero-based cursor
|
|
offset to <code>POST /api/script/completions</code>, and the response is an <code>items</code> array. Each item carries a
|
|
label, a kind already normalised to CodeMirror's own completion type names, a <code>detail</code> (the
|
|
signature, shown dim beside the label), a <code>documentation</code> (the XML <code><summary></code>, rendered to plain
|
|
text by Roslyn and shown in the popup's info pane) and an <code>insertText</code>.</p>
|
|
<p>Completion is Roslyn in-process, over the very <code>ScriptOptions</code> — the same references and imports —
|
|
that the run compiles the script with, so the session shell's members and the runtime API surface
|
|
complete for real rather than by name matching. The service prepends the synthesised
|
|
<code>using</code> / <code>using static</code> prefix those imports need and offsets the cursor by its length, so what the
|
|
list offers is what the evaluator will see. A cancelled request is answered 499, and a result that
|
|
arrives after the editor has moved on is dropped rather than shown.</p>
|
|
<p>Picking a method inserts the server-formatted call with each argument as a Tab stop, so the cursor
|
|
lands on the first parameter and Tab walks the rest; a method with no parameters inserts as <code>()</code>.
|
|
Properties, fields, types and keywords insert as their plain text — a snippet there would be noise.</p>
|
|
<h2 id="saving">Saving</h2>
|
|
<p>There is no Save button. Every keystroke in either field updates the model and schedules one save
|
|
500 ms after the last edit, and the pill beside the title reports the state: Idle, Dirty, Staging…,
|
|
Staged, or Error with the message in its tooltip. Staged means the server runtime holds the value —
|
|
its tooltip says so, because a staged script is not yet a committed project.</p>
|
|
<p>The write is a single PUT carrying the script text, the title and the content hash the last load or
|
|
save handed back. Each field is applied only when the body carries it. The response returns the new
|
|
hash to chain into the next save.</p>
|
|
<p>Two prompts guard the edges, each with three buttons because neither is a yes/no question:</p>
|
|
<ul>
|
|
<li><strong>Unsaved Changes</strong>, raised when the Control Tree tries to move the selection off a command whose
|
|
save is still pending: Save & switch flushes and then allows the switch, Discard drops the pending
|
|
write, Cancel keeps the selection where it is.</li>
|
|
<li><strong>Script changed elsewhere</strong>, raised when the server rejects the save because the hash no longer
|
|
matches — another tab, or a project reload, changed the command underneath. The rejection carries
|
|
the server's current text, title and hash, so the panel can offer Discard & reload, Force
|
|
overwrite, or Cancel without a second round trip.</li>
|
|
</ul>
|
|
<p>The panel snapshots its command path at mount, and the autosave closes over that snapshot rather
|
|
than over the live selection, so a flush can never land on whichever command happens to be selected
|
|
when it fires. After each successful save the tree relabels the node in place instead of rebuilding
|
|
the branch, which would remount the editor mid-edit.</p>
|
|
<h2 id="the-compile-gate">The Compile Gate</h2>
|
|
<p>A script that does not compile does nothing at run time: the command reports the compile failure
|
|
into the run's message stream and yields no work, so the run continues without it. Starting a run
|
|
therefore compile-checks every enabled script first — with the same script options and globals type
|
|
the evaluator uses — and refuses to start when any of them has an error, naming the first offender's
|
|
title, path, diagnostic id, message and line. The SPA's Start sends nothing to bypass that check, so
|
|
the refusal is what a user sees. The same check is also an endpoint of its own, per command and for
|
|
the whole mission.</p>
|
|
<h2 id="the-two-clients">The Two Clients</h2>
|
|
<p>The desktop client edits the same command in AvalonEdit: a bold Script Title label with its text
|
|
box, a Script Text label, and the editor with C# syntax highlighting and a line-number gutter,
|
|
bound to the command through an attached behaviour. There is no completion popup and no autosave —
|
|
the binding writes straight into the command as the text changes.</p>
|
|
<h2 id="source-code-path">Source Code Path</h2>
|
|
<p>See <a class="xref" href="../../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
|
<h3 id="web-application">Web Application</h3>
|
|
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
|
|
<ul>
|
|
<li><code>wwwroot-src/src/components/mission/ScriptCommandPanel.vue</code> — this panel: the title row sharing
|
|
its line with the autosave indicator, the editor below it, the 500 ms autosave, the two
|
|
three-button prompts, the path snapshot taken at mount, and the change notice that relabels the
|
|
tree node.</li>
|
|
<li><code>wwwroot-src/src/components/widgets/TextEditor.vue</code> — the CodeMirror 6 wrapper: language and
|
|
read-only swapped through compartments, CRLF normalised on the way in so an unedited file cannot
|
|
dirty the autosave, an opt-in completion source that overrides the language's own, and a widened
|
|
monospace popup so full signatures fit before the dim detail column truncates.</li>
|
|
<li><code>wwwroot-src/src/components/widgets/missionScriptLanguage.ts</code> — the <code>mission-script</code> mode: the
|
|
keyword set, the string and character rules, numbers, comments, call-site tagging, and its own
|
|
highlight style.</li>
|
|
<li><code>wwwroot-src/src/components/mission/csharpCompletionSource.ts</code> — the completion source: fires on
|
|
an identifier prefix or an explicit request, sends the whole document with the cursor offset,
|
|
drops stale results, and applies every candidate as a snippet.</li>
|
|
<li><code>wwwroot-src/src/api/scriptCompletion.ts</code> — the typed wrapper over the completion endpoint and the
|
|
kind union that maps straight onto CodeMirror's completion types.</li>
|
|
<li><code>wwwroot-src/src/api/mission.ts</code> — the script command shape (text, title, content hash), its
|
|
loader, the save that carries the expected hash, and the conflict error that carries the server's
|
|
current copy.</li>
|
|
<li><code>wwwroot-src/src/composables/useAutoSave.ts</code> — the debounce, the state machine and the conflict
|
|
recovery behind the panel's saving, saved and error states.</li>
|
|
<li><code>wwwroot-src/src/components/widgets/AutoSaveIndicator.vue</code> — the status pill beside the title.</li>
|
|
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code> — funnels every selection change
|
|
through the active panel's switch gate, which is how the Unsaved Changes prompt gets its say.</li>
|
|
<li><code>wwwroot-src/src/components/controlTree/missionItemTypes.ts</code> — maps the <code>script</code> kind to this
|
|
panel and gives it no section children, so the whole editor lives on the command node.</li>
|
|
<li><code>wwwroot-src/src/i18n/en/mission.ts</code> — the panel's wording: both prompts, their buttons, and the
|
|
load and save error contexts.</li>
|
|
<li><code>Missions/ScriptCompletionController.cs</code> — <code>POST /api/script/completions</code>: a thin wrapper that
|
|
returns the items, 499 on cancellation and 500 with the message on failure.</li>
|
|
<li><code>Missions/ScriptCompletionService.cs</code> — the singleton holding one workspace, built from the same
|
|
script options the session evaluates with, and the snippet insert text it builds for methods.</li>
|
|
<li><code>Missions/ScriptCompileCheckService.cs</code> — compiles a script without running it, and walks the
|
|
mission for every enabled one; it backs the two compile-check endpoints and the pre-start gate.</li>
|
|
<li><code>Missions/MissionController.cs</code> — the single script PUT with its hash-based concurrency, the
|
|
content hash stamped into the command snapshot, and the two compile-check endpoints.</li>
|
|
<li><code>Execution/ExecutionController.cs</code> — the start gate that compile-checks the enabled scripts and
|
|
refuses to run while one of them has an error.</li>
|
|
</ul>
|
|
<h3 id="hiapi-engine">HiAPI Engine</h3>
|
|
<ul>
|
|
<li><code>HiNc/SessionCommands/ScriptCommand.cs</code> — the model: the title and text, the Program-category
|
|
catalog registration, the XML round-trip that puts the script into the project file, the
|
|
evaluation against the session shell with a compile failure reported into the run's message
|
|
stream, the returned actions yielded into the run, and the label rule that brackets the title
|
|
after the command name.</li>
|
|
</ul>
|
|
<h2 id="see-also">See Also</h2>
|
|
<ul>
|
|
<li><a class="xref" href="NcCodeCommand-panel.html">NcCodeCommand Panel</a> — the other command that stores its text in the project, and the one that ships no editor chrome</li>
|
|
<li><a href="../../../manual/run/the-other-commands.html">The Other Commands</a> — the task this command serves, beside the settings and output kinds</li>
|
|
<li><a href="index.html">Mission</a> — the rest of the command panels</li>
|
|
</ul>
|
|
|
|
</article>
|
|
|
|
<div class="contribution d-print-none">
|
|
</div>
|
|
|
|
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
|
|
|
</div>
|
|
|
|
<div class="affix">
|
|
<nav id="affix"></nav>
|
|
</div>
|
|
</main>
|
|
|
|
<div class="container-xxl search-results" id="search-results"></div>
|
|
|
|
<footer class="border-top text-secondary">
|
|
<div class="container-xxl">
|
|
<div class="flex-fill">
|
|
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|