nsh
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNative Shell
Native Shell
One app, written in Rust, in TSX, or in both, rendered through each platform's own
views on the same Rust engine. Follow the user’s chosen language and delivery model.
When neither is specified, prefer Rust for an app shipped in its binary.
一个应用可以使用 Rust、TSX 或两者编写,并通过同一 Rust 引擎由各平台自己的
原生视图渲染。遵循用户选择的语言和交付模式。
如果两者都未指定,对于以 binary 形式交付的应用,优先使用 Rust。
Choose the Mode, Then Read Its Page
选择模式,然后阅读对应页面
| 1. Rust (preferred) | 2. Rust with TSX | 3. TSX | |
|---|---|---|---|
| Choose it when | The app ships in its binary; medium and large apps, demanding logic | A Rust core, plus screens that change often or arrive as signed packages | UI delivered at run time, with no Rust of your own |
| Runs on | The engine and your crate; no JavaScript VM | QuickJS (the browser's engine on the web) with your crate | QuickJS (the browser's engine on the web) |
| Start | | | |
| How to recognize one | | | |
| Edits | Rebuild and restart | TSX hot, Rust restarts | Hot |
| Read first | rust.md | mixed.md, and rust.md for the crate | tsx.md |
| Components | rust-ui.md | Both | tsx.md, |
| Tests | rust-testing.md | mixed.md "Tests on both sides" | tsx.md, testing guide |
| Whole app | rust-recipe.md ( | | tsx-recipe.md ( |
In an existing project, stay in its mode unless the user requests a change. For a new
app, honor the requested mode; otherwise use the table above; a Rust app can gain TSX later, because it already has a
. tooling.md covers the commands, debugging, platforms,
capabilities, packaging and updates in all three.
#[native_module]The rule of every mode: a component runs once, and only the bindings that read a
changed signal run again. A value read in a component body is a snapshot.
| 1. Rust(首选) | 2. Rust 与 TSX | 3. TSX | |
|---|---|---|---|
| 选择条件 | 应用以 binary 形式交付;适合中大型应用和逻辑密集型场景 | 以 Rust 为核心,界面经常变化或以签名包形式交付 | 在运行时交付 UI,且不使用自己的 Rust |
| 运行于 | 引擎与你的 crate;无 JavaScript VM | QuickJS(Web 上浏览器使用的引擎)与你的 crate | QuickJS(Web 上浏览器使用的引擎) |
| 初始化 | | | |
| 识别方式 | | | |
| 编辑方式 | 重新构建并重启 | TSX 热更新,Rust 重启 | 热更新 |
| 首先阅读 | rust.md | mixed.md,以及关于 crate 的 rust.md | tsx.md |
| 组件 | rust-ui.md | 两者都需要 | tsx.md、 |
| 测试 | rust-testing.md | mixed.md 中的“双方测试” | tsx.md、测试指南 |
| 完整应用 | rust-recipe.md( | | tsx-recipe.md( |
在现有项目中,除非用户要求更改,否则保持其模式不变。对于新应用,遵循请求的模式;
否则使用上表;Rust 应用之后可以加入 TSX,因为它已经具有
。tooling.md 涵盖三种模式下的命令、调试、平台、
capabilities、打包和更新。
#[native_module]所有模式的共同规则:组件只运行一次,只有读取了已变化信号的绑定才会
再次运行。 在组件主体中读取的值是快照。
First App or Existing Project
首个应用或现有项目
Resolve paths relative to this skill’s directory, not the app’s working
directory. Read only the mode and topic pages needed for the task.
references/- Existing project: inspect , the entry and, for Rust,
nsh.json. Keep its structure, dependency sources and mode. Use the project’s CLI version.Cargo.toml - First app: run . For Rust or mixed, also check
nsh --version. If a tool is missing, read tooling.md for setup and the prerequisites of the requested target.cargo --version - Read the guides below and the selected mode page. Initialize with the table’s
explicit in the user’s chosen location. Work from the generated project, preserving its manifest and entry wiring; the quick-start snippets below illustrate edits, rather than replacing all generated files.
--template - Get the generated app through and
nsh checkbefore expanding it. Then implement the requested flow and use the mode’s verification loop below. Check the visible result on the requested target when available; report any verification that the environment cannot perform.nsh test
相对于此 skill 的目录解析 路径,而不是应用的工作目录。
只读取任务所需的模式和主题页面。
references/- 现有项目: 检查 、入口,对于 Rust 项目还要检查
nsh.json。 保持项目结构、依赖来源和模式不变。使用项目自己的 CLI 版本。Cargo.toml - 首个应用: 运行 。对于 Rust 或 mixed 模式,还要检查
nsh --version。 如果缺少工具,请阅读 tooling.md, 了解设置方式和请求目标平台的先决条件。cargo --version - 阅读下方指南和选定模式的页面。在用户选择的位置使用表格中明确的
进行初始化。以生成的项目为基础,保留其 manifest 和入口连接; 以下快速入门代码片段仅演示如何修改,而不是替换所有生成的文件。
--template - 先让生成的应用通过 和
nsh check,然后再扩展它。 接着实现请求的流程,并使用该模式的验证循环。 目标平台可用时,检查可见结果;报告环境无法执行的任何验证。nsh test
Read the Guides First
首先阅读指南
Two guides hold the rules this skill assumes. They are requirements, not
inspiration. Read the guide file itself; do not answer from this page, from a
similar file in the codebase, or from training data.
| Guide | Read before |
|---|---|
Design Guides, skill | Choosing components, layout, spacing, hierarchy, color, density, interaction states, overlays, motion, interface copy |
| Coding Guides | App structure, what runs once, state ownership, keys, theme, events, focus, async, lists, public API, naming, testing |
Read the Design Guides first when the change has a visible surface. If the design
skill is not installed, fetch . The coding
guide is a verbatim copy of , so a link in
it such as means , and
means .
https://nsh.dev/docs/design-guides.mdhttps://nsh.dev/docs/coding-guides.md./reactivity.mdhttps://nsh.dev/docs/reactivity.md../modules/nsh.mdhttps://nsh.dev/modules/nsh.md以下两份指南包含此 skill 所依据的规则。它们是要求,而不是灵感。
必须阅读指南文件本身;不要根据本页、代码库中的类似文件或训练数据作答。
| 指南 | 阅读时机 |
|---|---|
Design Guides、skill | 选择组件、布局、间距、层级、颜色、密度、交互状态、浮层、动效、界面文案 |
| Coding Guides | 应用结构、只运行一次的内容、状态归属、keys、主题、事件、焦点、异步、列表、公共 API、命名、测试 |
变更涉及可见界面时,先阅读 Design Guides。如果尚未安装 design skill,请获取
。Coding guide 是
的逐字副本,因此其中的链接,例如
,表示 ,而
表示 。
https://nsh.dev/docs/design-guides.mdhttps://nsh.dev/docs/coding-guides.md./reactivity.mdhttps://nsh.dev/docs/reactivity.md../modules/nsh.mdhttps://nsh.dev/modules/nsh.mdCoding Guides section map
Coding Guides 章节映射
Read the whole guide for a new app, module or feature. For a narrow change, read
"Understand what runs once and what runs again" and "Rules for coding agents"
first, then the section for the change ().
grep -n '^## ' references/coding-guides.md| Section | Read when |
|---|---|
| Architecture at a glance | Always; layers, an app's files, the store |
| Bootstrap and root ownership | |
| Understand what runs once and what runs again | Always; components, bindings, owners, context |
| Choose the right unit | Plain function, component or Rust |
| State ownership | Where state lives, controlled values, feedback loops |
| Stable identity | Keys, routes, test ids |
| Rendering and composition | Component bodies, |
| Behavior and presentation boundary | What |
| Theme and styling | Tokens, the Tailwind scale, state styles, text size |
| Events, commands, and focus | Presses, shortcuts, decisions as props, focus, overlays |
| Async work and side effects | |
| Layout, measurement, and scrolling | Flex defaults, |
| Lists, tables, and large data | |
| Public API design | Anything other code imports |
| Platform and capability boundaries | |
| File and naming conventions | Names of components, props, events, states |
| Testing strategy | |
| Performance rules | Before adding a cache; |
| Common failure modes | Before finishing |
| Rules for coding agents | Always when an agent writes code |
| Implementation checklist | Before finishing; run every item against the work |
新应用、模块或功能需要阅读整份指南。对于范围较窄的变更,先阅读
“Understand what runs once and what runs again”和“Rules for coding agents”,
然后阅读变更对应的章节()。
grep -n '^## ' references/coding-guides.md| 章节 | 阅读时机 |
|---|---|
| 架构概览(Architecture at a glance) | 始终;分层、应用文件、store |
| Bootstrap 与 root 归属 | |
| 理解哪些内容只运行一次、哪些会再次运行 | 始终;components、bindings、owners、context |
| 选择合适的单元 | 普通函数、component 或 Rust |
| 状态归属 | 状态存放位置、受控值、反馈循环 |
| 稳定标识 | keys、routes、test ids |
| 渲染与组合 | 组件主体、 |
| 行为与呈现边界 | |
| 主题与样式 | tokens、Tailwind scale、状态样式、字号 |
| 事件、命令与焦点 | 按压、快捷键、以 props 传递的 decisions、焦点、overlays |
| 异步工作与副作用 | |
| 布局、测量与滚动 | Flex defaults、 |
| 列表、表格与大型数据 | |
| 公共 API 设计 | 其他代码导入的所有内容 |
| 平台与 capability 边界 | |
| 文件与命名约定 | components、props、events、states 的名称 |
| 测试策略 | |
| 性能规则 | 添加 cache 之前; |
| 常见失败模式 | 完成之前 |
| Coding Agent 规则 | Agent 编写代码时始终阅读 |
| 实现检查清单 | 完成之前;对工作逐项执行 |
Non-negotiables
不可妥协项
A floor, not a substitute for the guides.
- Never invent an API. Look the name up in the crate's source (Rust) or in
(TSX), then its reference page. Do not write by analogy with another framework.
.nsh/types - Components run once. In Rust, pass a closure or a signal where a value must stay
current: . In TSX, read props and signals in JSX or a closure; do not destructure props.
text(move || format!("{}", count.get())) - One owner per state. A page's draft is a signal of that page; shared state is a store with private signals. In Rust with TSX, one side owns each piece of state.
- The look is the app's. /
nsh_basehas behavior and no look, and NSH has no styled component library. Draw with theme tokens:nsh/basein Rust,theme().primaryin TSX. Wrap each base component once in the app's own UI module.bg-primary - Parts draw nothing until styled. A switch with no track and thumb style shows no switch, and a test still passes. Style every part, and look at the result.
- Use the semantic component. Button, Menu, Popover, Sheet, Dialog and Select bring focus, keyboard, dismissal and accessibility. Do not rebuild them from a view.
- Long data goes in a virtualized list, with per-item state in data keyed by id, never in a signal created in a row: cells are reused for other rows.
- A decision the system needs at once is a prop, set beforehand (,
pop_on_back,close_on_escape), never a callback returning a boolean.disabled - Do not change NSH to fit an app. Solve it in the app first: its own components, a Rust crate, or a native component.
- TSX has no DOM, no Node and no npm UI. Standard modules are exactly ,
buffer,console,crypto,fs/promises,net,os,path,process,url,websocket.zlib
这些是最低要求,不能替代指南。
- 绝不臆造 API。 先在 crate 源码(Rust)或 (TSX)中查找名称, 再查阅对应的 reference page。不要根据其他 framework 类推。
.nsh/types - 组件只运行一次。 在 Rust 中,如果某个值必须保持最新,请传入 closure 或
signal:。在 TSX 中,在 JSX 或 closure 中读取 props 和 signals;不要对 props 解构。
text(move || format!("{}", count.get())) - 每项状态只有一个 owner。 页面的草稿是该页面的 signal;共享状态是使用 私有 signals 的 store。在 Rust 与 TSX 混合模式中,每项状态都由其中一侧拥有。
- 应用决定外观。 /
nsh_base提供行为但不提供外观,而且 NSH 没有 styled component library。使用 theme tokens 绘制界面:在 Rust 中是nsh/base,在 TSX 中是theme().primary。在应用自己的 UI module 中将每个 base component 包装一次。bg-primary - 设置样式前,parts 不会绘制任何内容。 没有 track 和 thumb 样式的 switch 即使测试通过也不会显示。为每个 part 设置样式,并查看实际结果。
- 使用语义化 component。 Button、Menu、Popover、Sheet、Dialog 和 Select 自带 focus、keyboard、dismissal 和 accessibility。不要基于 view 重新实现它们。
- 大量数据应放入 virtualized list, 每项状态以 id 为 key 保存在数据中, 绝不能保存在 row 中创建的 signal 中,因为 cells 会被其他 rows 复用。
- 系统需要立即做出的 decision 应作为 prop, 并预先设置(、
pop_on_back、close_on_escape),绝不能使用返回 boolean 的 callback。disabled - 不要为了适应应用而修改 NSH。 首先在应用中解决:使用应用自己的 components、 Rust crate 或 native component。
- TSX 没有 DOM、Node 或 npm UI。 标准模块严格限定为 、
buffer、console、crypto、fs/promises、net、os、path、process、url、websocket。zlib
The Loop
执行循环
Run your mode's loop before calling work done. Prefer check and headless tests to full
builds while working.
sh
undefined宣布工作完成前,运行所选模式的验证循环。工作期间优先使用 check 和 headless tests,
而不是完整 builds。
sh
undefinedRust
Rust
cargo check --all-targets # or nsh check, which also checks TS tests
cargo test # the real UI, headless, with nsh_testing::Headless
nsh run # look at it; --target ios, android, web, macos, linux, windows
cargo check --all-targets # or nsh check, which also checks TS tests
cargo test # the real UI, headless, with nsh_testing::Headless
nsh run # look at it; --target ios, android, web, macos, linux, windows
Rust with TSX
Rust with TSX
nsh check # cargo check, then tsc against the types generated from Rust
nsh build # every warn is a finding: undocumented exports, unknown classes
nsh test # cargo test, then *.test.tsx in a runner linked with the crate
nsh run
nsh check # cargo check, then tsc against the types generated from Rust
nsh build # every warn is a finding: undocumented exports, unknown classes
nsh test # cargo test, then *.test.tsx in a runner linked with the crate
nsh run
TSX
TSX
nsh check # the only type check
nsh build # the bundler's errors: nsh check does not see text in a View
nsh test # *.test.tsx, headless
nsh run
Headless tests prove behavior, not the look: take a screenshot or run the app for
anything visible. In TSX, passing one of `nsh check` and `nsh build` proves little without
the other; [the table in tsx.md](references/tsx.md#who-reports-what) shows who reports what.nsh check # the only type check
nsh build # the bundler's errors: nsh check does not see text in a View
nsh test # *.test.tsx, headless
nsh run
Headless 测试证明行为,而不是外观:对于任何可见内容,请截取屏幕截图或运行应用。
在 TSX 中,仅通过 `nsh check` 和 `nsh build` 中的一个几乎无法证明什么;
[tsx.md 中的表格](references/tsx.md#who-reports-what) 说明了各自负责报告的内容。Quick Start in Rust
Rust 快速入门
rust
use nsh_base::{button, theme};
use nsh_core::prelude::*;
#[native_module("app/native")]
fn native(registry: &mut Registry) {
registry.register::<App>();
}
#[component]
pub fn App() -> impl IntoElement {
let count = signal(0_u32);
view()
.flex_1()
.items_center()
.justify_center()
.gap_4()
.bg(move || theme().background)
// A closure is a binding: it runs again when `count` changes.
.child(text(move || format!("Count: {}", count.get())).text_color(move || theme().foreground))
.child(
button()
.px(px(20.0))
.py(px(12.0))
.rounded(move || theme().radius)
.bg(move || theme().primary)
.active(|s| s.bg(move || theme().primary.opacity(0.9)))
.on_press(move || count.update(|c| *c += 1))
.child(text("Tap").text_color(move || theme().primary_foreground)),
)
}json
{ "name": "My App", "rust": ".", "root": "App" }rust
// tests/app.rs (add matching dev-dependencies from references/rust-testing.md)
use nsh_engine::{EngineConfig, Root};
use nsh_testing::Headless;
#[test]
fn a_tap_counts() {
let mut app = Headless::start(EngineConfig::new(Root::of::<nsh_app_my_app::App>())).unwrap();
app.wait_for("Count: 0").unwrap();
app.press("Tap").unwrap();
app.wait_for("Count: 1").unwrap();
}The same app in TSX, and the TSX forms, are in tsx.md.
Rust names are in TSX ( is ).
snake_casecamelCaseon_open_changeonOpenChangerust
use nsh_base::{button, theme};
use nsh_core::prelude::*;
#[native_module("app/native")]
fn native(registry: &mut Registry) {
registry.register::<App>();
}
#[component]
pub fn App() -> impl IntoElement {
let count = signal(0_u32);
view()
.flex_1()
.items_center()
.justify_center()
.gap_4()
.bg(move || theme().background)
// A closure is a binding: it runs again when `count` changes.
.child(text(move || format!("Count: {}", count.get())).text_color(move || theme().foreground))
.child(
button()
.px(px(20.0))
.py(px(12.0))
.rounded(move || theme().radius)
.bg(move || theme().primary)
.active(|s| s.bg(move || theme().primary.opacity(0.9)))
.on_press(move || count.update(|c| *c += 1))
.child(text("Tap").text_color(move || theme().primary_foreground)),
)
}json
{ "name": "My App", "rust": ".", "root": "App" }rust
// tests/app.rs (add matching dev-dependencies from references/rust-testing.md)
use nsh_engine::{EngineConfig, Root};
use nsh_testing::Headless;
#[test]
fn a_tap_counts() {
let mut app = Headless::start(EngineConfig::new(Root::of::<nsh_app_my_app::App>())).unwrap();
app.wait_for("Count: 0").unwrap();
app.press("Tap").unwrap();
app.wait_for("Count: 1").unwrap();
}同一个应用的 TSX 版本及 TSX 写法见 tsx.md。Rust 的
名称在 TSX 中为 ( 对应 )。
snake_casecamelCaseon_open_changeonOpenChangeDocumentation
文档
Start with the bundled mode pages and recipes; they work without an NSH checkout.
For exact APIs, use the project’s in TSX and its resolved dependency
source in Rust. reports dependency manifests
and their source locations; use those paths rather than assuming a Cargo cache path.
Run to generate missing TS declarations.
.nsh/typescargo metadata --format-version 1nsh checkPaths starting with , or in the references identify
files in the NSH repository; they are optional source pointers, not files in the
installed skill or the user’s app. Use them when a checkout is available. Otherwise,
use the bundled recipes, the online docs below, or the corresponding file at
at the project’s matching tag or revision.
A pointer corresponds to ;
and similarly map to site paths.
examples/crates/website/https://github.com/longbridge/nshwebsite/docs/foo.mdhttps://nsh.dev/docs/foo.mdwebsite/elements/website/modules/The site follows the latest release and may describe a newer API than the project
uses. Preserve the project’s version and verify examples against its types or source.
Fetch individual pages as needed; use only for broad exploration.
llms-full.txt- Find a page: , then load its Markdown;
https://nsh.dev/llms.txtfor broad reference.https://nsh.dev/llms-full.txt - Rust: ,
https://nsh.dev/docs/rust.md,native-components.md.networking.md - An element or component: .
https://nsh.dev/elements/{name}.md - A module: :
https://nsh.dev/modules/{name}.md,nsh.md,nsh-base.md,nsh-mobile.md,nsh-desktop.md,style-reference.md,tailwind-reference.md.standard-modules.md - A guide: :
https://nsh.dev/docs/{name}.md,reactivity.md,layout.md,navigation.md,lists.md,forms-and-keyboard.md,platform-specific.md.testing-and-trace.md
先从内置的模式页面和 recipes 开始;它们无需 NSH checkout 即可使用。
对于精确 API,TSX 使用项目的 ,Rust 使用已解析的 dependency source。
会报告 dependency manifests 及其 source locations;
请使用这些路径,不要假定 Cargo cache 路径。
运行 生成缺失的 TS declarations。
.nsh/typescargo metadata --format-version 1nsh check以 、 或 开头的路径表示 NSH repository 中的文件;
它们只是可选的 source pointers,并非已安装 skill 或用户应用中的文件。有 checkout 时可使用它们。
否则,使用内置 recipes、下方在线文档,或 GitHub URL 中与项目匹配 tag 或 revision
对应的文件。
pointer 对应 ;
和 也分别映射到相应的 site paths。
examples/crates/website/website/docs/foo.mdhttps://nsh.dev/docs/foo.mdwebsite/elements/website/modules/站点内容以最新 release 为准,可能描述比项目所用版本更新的 API。
保持项目版本不变,并根据其 types 或 source 验证示例。
按需获取单个页面;仅在广泛探索时使用 。
llms-full.txt- 查找页面: ,然后加载其 Markdown;
https://nsh.dev/llms.txt用于广泛参考。https://nsh.dev/llms-full.txt - Rust: 、
https://nsh.dev/docs/rust.md、native-components.md。networking.md - 元素或 component: 。
https://nsh.dev/elements/{name}.md - 模块: :
https://nsh.dev/modules/{name}.md、nsh.md、nsh-base.md、nsh-mobile.md、nsh-desktop.md、style-reference.md、tailwind-reference.md。standard-modules.md - 指南: :
https://nsh.dev/docs/{name}.md、reactivity.md、layout.md、navigation.md、lists.md、forms-and-keyboard.md、platform-specific.md。testing-and-trace.md
Working on NSH itself
开发 NSH 本身
This skill is for building apps. In a checkout of , follow its
and as well.
longbridge/nshAGENTS.mddocs/dev/此 skill 用于构建应用。在 的 checkout 中,还应遵循其
和 。
longbridge/nshAGENTS.mddocs/dev/