- 开发工具
- 数据科学
【免费下载链接】archived-desktop-app
The old electron based nteract notebook
本指南以 nteract 仓库中packages/presentational-components/src/components/prompt.md文档为主体,系统讲解Prompt组件的作用、props 语义与在 Notebook 前端中的实际接入方式。读完本文,你将掌握如何用counter、running、queued、blank四个 props 复刻 Jupyter 风格的In [n]/Out [n]提示符,并理解它如何与Input容器、Redux 状态层配合,完成单元格执行状态的实时展示。
Prompt 组件是什么
Prompt组件通常作为Input组件的子组件出现,承担两个职责:
- 输入入口的视觉指示:告诉用户当前区域是可供输入/执行单元格的区域;
- 单元格状态信息展示:把单元格当前处于“未执行、正在执行、排队中、已执行过 N 次”等状态,以 Jupyter 用户熟悉的形式呈现出来。
在 nteract 的组件分层中,Prompt属于“展示型组件(presentational component)”,定义于 packages/presentational-components/src/components/prompt.tsx。它不感知 Redux 状态,只根据传入的 props 决定渲染什么文本,因此既可以在纯 React 环境下独立使用,也可以被上层“有状态组件”包一层后接入数据流。
快速上手:从导入到第一个 Prompt
从@nteract/presentational-components导入:
import { Prompt } from "@nteract/presentational-components"该包的统一出口在 packages/presentational-components/src/index.ts,其中同时导出了Prompt与PromptBuffer:
import { Prompt, PromptBuffer } from "./components/prompt"; // ... export { // ... Prompt, PromptBuffer, // ... }不带任何 props 的<Prompt />会渲染一对空括号:
<Prompt />渲染结果对应 Jupyter 中尚未执行代码时的默认提示符:
[ ]用 counter 展示执行计数
counter接受一个数字,渲染时会把该数字填进括号内:
<Prompt counter={12} />[12]在 Jupyter 生态中,这个数字通常是 Jupyter kernel 返回的execution_count,表示当前单元格在整个会话中被执行到的序号。用户在jupyter console或 IPython 中常见的In [n]/Out [n]中的 n,就是这个计数。源码注释中给出了对应的经典形态:
In [1]: 2 + 2 Out[1]: 4 In [2]: "woohoo" Out[2]: 'woohoo'在 nteract 的数据流中,execution_count保存在单元格的 Immutable 记录里(cell.get("execution_count", undefined)),由有状态层读取后传入展示层,详见后文“有状态接入”一节。
用 running 表示正在执行
传入running布尔 prop,组件会在括号中间渲染一个星号*,向用户标明该单元格正处于执行中:
<Prompt counter={12} running />[*]星号是 Jupyter 生态约定俗成的“执行中”标志——用户看到[*]就能立刻意识到内核正在运行该单元格,且尚未产生输出。
用 queued 表示排队等待执行
传入queued布尔 prop,组件渲染省略号形态的提示符:
<Prompt counter={12} queued />[…]queued通常配合“Run all cells”(运行全部单元格)这类批量执行功能使用:当多个单元格被一次性提交执行时,尚未轮到执行的单元格以[…]呈现,视觉上与“正在执行”的[*]、以及“已执行”的[n]区分开。
用 blank 渲染空白提示符
传入blank后,Prompt 不再渲染括号或任何指示符,只保留一个留白区域:
<Prompt blank />(空,不渲染 [ ])这用于 Markdown 单元格等不需要执行计数的场景。仓库为此专门提供了派生组件PromptBuffer,它把blank默认置为true:
export const PromptBuffer = styled(Prompt)``; PromptBuffer.defaultProps = { blank: true, };也就是说,<PromptBuffer />等价于<Prompt blank />。在Prompt的 styled 样式中,min-height: 22px正是“为<Prompt blank />创建缓冲区域”而设置的(见源码注释),保证 Markdown 单元格的提示符区域与代码单元格高度对齐。
源码级解析:promptText 的优先级规则
prompt.tsx中用纯函数promptText统一决定渲染文本,这是理解整个组件行为的关键:
function promptText(props: PromptProps): string { if (props.running) { return "[*]"; } if (props.queued) { return "[…]"; } if (typeof props.counter === "number") { return `[${props.counter}]`; } if (props.blank) { return ""; } return "[ ]"; }注意其中的判定优先级:
running优先级最高,其次是queued;- 只有既非 running 也非 queued 时,
counter才会被渲染; counter判定使用typeof props.counter === "number",因此传入0也会正常显示[0](第 0 次执行是合法状态),而null、undefined则不会进入此分支;blank的优先级低于前三者,仅在没有其他状态命中时生效;- 兜底返回
"[ ]"。
四个 props 的默认值定义在Prompt.defaultProps中,全部为“未激活”状态:
Prompt.defaultProps = { counter: null, running: false, queued: false, blank: false, };PromptProps接口还允许传入className,配合 styled-components 实现样式的组合与覆盖。
外观与主题定制
Prompt是基于styled-components构建的:先把纯渲染逻辑放进BarePrompt,再通过styled(BarePrompt)注入样式,导出最终的Prompt:
export const Prompt = styled(BarePrompt)` font-family: monospace; font-size: 12px; line-height: 22px; min-height: 22px; padding: 9px 0; text-align: center; color: var(--theme-cell-prompt-fg, black); background-color: var(--theme-cell-prompt-bg, #fafafa); `;几个值得注意的细节:
- 等宽字体:
font-family: monospace保证[1]、[10]、[100]宽度一致,提示符列对齐不跳动; - 主题变量:颜色通过 CSS 变量
--theme-cell-prompt-fg与--theme-cell-prompt-bg提供,并给出默认值black与#fafafa。这意味着上层应用可以在全局样式(参见 packages/styles 下的主题文件)中覆盖这两个变量,即可整体改变提示符配色,无需逐个实例传参。
与 Input、Source 组合成单元格输入区
Prompt很少单独出现,它通常与Input、Source一起构成单元格的输入区块。Input是一个轻量容器组件(见 packages/presentational-components/src/components/input.md 与 input.tsx),提供hiddenprop 控制子节点是否渲染,其 styled 样式通过 flex 布局把Prompt与Source排布在同一行:
export const Input = styled(BareInput)` & { display: flex; flex-direction: row; } // ... & ${Prompt} { flex: 0 0 auto; } & ${Source} { flex: 1 1 auto; overflow: visible; background-color: var(--theme-cell-input-bg, #fafafa); } `;Prompt使用flex: 0 0 auto固定宽度(不伸缩),Source使用flex: 1 1 auto占据剩余空间。标准组合方式:
const { Prompt, Source } = require("@nteract/presentational-components"); <Input> <Prompt/> <Source/> </Input>有状态接入:从 Redux 状态到提示符文本
展示层Prompt只负责“翻译”props,真正的数据来自有状态层。在 packages/stateful-components/src/inputs/prompt.tsx 中,存在一个同名的、通过connect连接 Redux 的容器组件:它从 notebook 模型的 transient 区域读取单元格status,从单元格记录读取execution_count,并通过 render-prop 把{ id, contentRef, status, executionCount }传给子函数:
if (model && model.type === "notebook") { status = model.transient.getIn(["cellMap", id, "status"]); const cell = selectors.notebook.cellById(model, { id }); if (cell) { executionCount = cell.get("execution_count", undefined); } }而 packages/stateful-components/src/cells/code-cell.tsx 中给出了默认的 prompt 槽位实现,展示了四种状态如何映射为最终文本:
<Prompt id={props.id} contentRef={props.contentRef}> {(props: PassedPromptProps) => { if (props.status === "busy") { return <React.Fragment>{"[*]"}</React.Fragment>; } if (props.status === "queued") { return <React.Fragment>{"[…]"}</React.Fragment>; } if (typeof props.executionCount === "number") { return <React.Fragment>{`[${props.executionCount}]`}</React.Fragment>; } return <React.Fragment>{"[ ]"}</React.Fragment>; }} </Prompt>这条调用链完整对应了prompt.md中的四个 props 语义:
| 单元格状态 | 数据来源 | 展示层 props | 渲染文本 |
|---|---|---|---|
| 执行中 | transient 中的status === "busy" | running | [*] |
| 排队中 | transient 中的status === "queued" | queued | […] |
| 已执行 | 单元格的execution_count | counter | [n] |
| 未执行 / Markdown | 无 | blank(或PromptBuffer) | 空 |
同时CodeCell还通过children.prompt暴露了插槽机制:调用方可以传入自定义的 prompt 渲染函数覆盖默认实现,实现如自定义提示符文本、隐藏执行计数等个性化需求(const prompt = children?.prompt || defaults.prompt;)。单元格渲染时,prompt 与编辑器一起被包进Input:
<Input id={id} contentRef={contentRef}> {prompt({ id, contentRef })} <Source className="nteract-cell-source"> <Editor id={id} contentRef={contentRef}>{editor}</Editor> </Source> </Input>相关组件:输入请求提示(PromptRequest)
与“展示执行状态”的Prompt不同,packages/stateful-components/src/outputs/input-prompts.tsx 中的PromptRequest负责内核发起的交互式输入请求(如密码、input()调用)。它根据selectors.notebook.cellPromptsById读取待处理的InputRequestMessage,渲染一个表单,提交时通过actions.sendInputReply({ value, contentRef })把用户输入回传内核:
<form onSubmit={this.handleSubmitPromptReply}> <label>{prompt.prompt}</label> <input type={prompt.password ? "password" : "text"} value={this.state.value} onChange={this.handleChange} /> <input type="submit"/> </form>注意实现细节:prompt.password为真时输入框类型切换为password,用于安全输入;且只展示prompts.last(undefined)即最后一条未处理的请求(源码注释 #5592 说明原因——状态中只保存单一值,其余请求已被处理)。它与展示型Prompt在职责上互补:Prompt反映单元格执行生命周期,PromptRequest处理内核的即时输入请求。
小结
Prompt是 nteract 组件体系中连接“视觉呈现”与“单元格状态”的关键节点:
- 四个 props 语义清晰:
counter(执行计数)、running([*])、queued([…])、blank(空白 / Markdown 单元格),判定优先级为 running → queued → counter → blank → 兜底空括号; - 纯展示、易定制:基于 styled-components 实现,颜色通过
--theme-cell-prompt-fg/--theme-cell-prompt-bg主题变量全局控制; - 上下层配合:展示层在 prompt.tsx,有状态接入在 stateful-components/src/inputs/prompt.tsx,默认行为定义于 code-cell.tsx;
- 生态扩展:
PromptBuffer提供空白提示符,PromptRequest处理内核输入请求,三者共同支撑完整的 Notebook 交互体验。
如需了解相邻组件(如Input、Source)的更多用法,可继续阅读 input.md 与 source.md;组件的统一导出见 index.ts。
- 开发工具
- 数据科学
【免费下载链接】archived-desktop-app
The old electron based nteract notebook
相关推荐
nteract presentational-components 中的 Input 组件:notebook 单元格输入容器的设计与实战
nteract presentational components 中的 Input 组件:notebook 单元格输入容器的设计与实战 本文是 nteract
开发工具数据科学给苹果已停更的旧Mac装上新系统:OpenCore Legacy Patcher一步步实操手册
给苹果已停更的旧Mac装上新系统:OpenCore Legacy Patcher一步步实操手册 升级时 2013 年的 iMac 在选盘环节直接被卡住,或者装完
开发工具数据科学Jupytext MyST Markdown 格式实战:从 nteract 参数化 Notebook 看代码单元格的 YAML 元数据表示
Jupytext MyST Markdown 格式实战:从 nteract 参数化 Notebook 看代码单元格的 YAML 元数据表示 导读 本文以 Jup
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考