开源 企业版 高校版 私有云 模力方舟 AI 队友
代码拉取完成,页面将自动刷新
加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
已有帐号? 立即登录
文件
main
分支 (1)
标签 (1)
main
v0.1.0
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
项目仓库所选许可证以仓库主分支所使用许可证为准
main
分支 (1)
标签 (1)
main
v0.1.0
克隆/下载
克隆/下载
提示
下载代码请复制以下命令到终端执行
为确保你提交的代码身份被 Gitee 正确识别,请执行以下命令完成配置
初次使用 SSH 协议进行代码克隆、推送等操作时,需按下述提示完成 SSH 配置
1 生成 RSA 密钥
2 获取 RSA 公钥内容,并配置到 SSH公钥
在 Gitee 上使用 SVN,请访问 使用指南
使用 HTTPS 协议时,命令行会出现如下账号密码验证步骤。基于安全考虑,Gitee 建议 配置并使用私人令牌 替代登录密码进行克隆、推送等操作
Username for 'https://gitee.com': userName
Password for 'https://userName@gitee.com': # 私人令牌
main
分支 (1)
标签 (1)
main
v0.1.0
editor.ts 6.48 KB
一键复制 编辑 原始数据 按行查看 历史
sanbucat 提交于 2026年03月31日 17:08 +08:00 . v2.1.88 反编译源码
import {
type SpawnOptions,
type SpawnSyncOptions,
spawn,
spawnSync,
} from 'child_process'
import memoize from 'lodash-es/memoize.js'
import { basename } from 'path'
import instances from '../ink/instances.js'
import { logForDebugging } from './debug.js'
import { whichSync } from './which.js'
function isCommandAvailable(command: string): boolean {
return !!whichSync(command)
}
// GUI editors that open in a separate window and can be spawned detached
// without fighting the TUI for stdin. VS Code forks (cursor, windsurf, codium)
// are listed explicitly since none contain 'code' as a substring.
const GUI_EDITORS = [
'code',
'cursor',
'windsurf',
'codium',
'subl',
'atom',
'gedit',
'notepad++',
'notepad',
]
// Editors that accept +N as a goto-line argument. The Windows default
// ('start /wait notepad') does not — notepad treats +42 as a filename.
const PLUS_N_EDITORS = /\b(vi|vim|nvim|nano|emacs|pico|micro|helix|hx)\b/
// VS Code and forks use -g file:line. subl uses bare file:line (no -g).
const VSCODE_FAMILY = new Set(['code', 'cursor', 'windsurf', 'codium'])
/**
* Classify the editor as GUI or not. Returns the matched GUI family name
* for goto-line argv selection, or undefined for terminal editors.
* Note: this is classification only — spawn the user's actual binary, not
* this return value, so `code-insiders` / absolute paths are preserved.
*
* Uses basename so /home/alice/code/bin/nvim doesn't match 'code' via the
* directory component. code-insiders → still matches 'code', /usr/bin/code →
* 'code' → matches.
*/
export function classifyGuiEditor(editor: string): string | undefined {
const base = basename(editor.split('')[0] ?? '')
return GUI_EDITORS.find(g => base.includes(g))
}
/**
* Build goto-line argv for a GUI editor. VS Code family uses -g file:line;
* subl uses bare file:line; others don't support goto-line.
*/
function guiGotoArgv(
guiFamily: string,
filePath: string,
line: number | undefined,
): string[] {
if (!line) return [filePath]
if (VSCODE_FAMILY.has(guiFamily)) return ['-g', `${filePath}:${line}`]
if (guiFamily === 'subl') return [`${filePath}:${line}`]
return [filePath]
}
/**
* Launch a file in the user's external editor.
*
* For GUI editors (code, subl, etc.): spawns detached — the editor opens
* in a separate window and Claude Code stays interactive.
*
* For terminal editors (vim, nvim, nano, etc.): blocks via Ink's alt-screen
* handoff until the editor exits. This is the same dance as editFileInEditor()
* in promptEditor.ts, minus the read-back.
*
* Returns true if the editor was launched, false if no editor is available.
*/
export function openFileInExternalEditor(
filePath: string,
line?: number,
): boolean {
const editor = getExternalEditor()
if (!editor) return false
// Spawn the user's actual binary (preserves code-insiders, abs paths, etc.).
// Split into binary + extra args so multi-word values like 'start /wait
// notepad' or 'code --wait' propagate all tokens to spawn.
const parts = editor.split('')
const base = parts[0] ?? editor
const editorArgs = parts.slice(1)
const guiFamily = classifyGuiEditor(editor)
if (guiFamily) {
const gotoArgv = guiGotoArgv(guiFamily, filePath, line)
const detachedOpts: SpawnOptions = { detached: true, stdio: 'ignore' }
let child
if (process.platform === 'win32') {
// shell: true on win32 so code.cmd / cursor.cmd / windsurf.cmd resolve —
// CreateProcess can't execute .cmd/.bat directly. Assemble quoted command
// string; cmd.exe doesn't expand $() or backticks inside double quotes.
// Quote each arg so paths with spaces survive the shell join.
const gotoStr = gotoArgv.map(a => `"${a}"`).join('')
child = spawn(`${editor}${gotoStr}`, { ...detachedOpts, shell: true })
} else {
// POSIX: argv array with no shell — injection-safe. shell: true would
// expand $() / backticks inside double quotes, and filePath is
// filesystem-sourced (possible RCE from a malicious repo filename).
child = spawn(base, [...editorArgs, ...gotoArgv], detachedOpts)
}
// spawn() emits ENOENT asynchronously. ENOENT on $VISUAL/$EDITOR is a
// user-config error, not an internal bug — don't pollute error telemetry.
child.on('error', e =>
logForDebugging(`editor spawn failed: ${e}`, { level: 'error' }),
)
child.unref()
return true
}
// Terminal editor — needs alt-screen handoff since it takes over the
// terminal. Blocks until the editor exits.
const inkInstance = instances.get(process.stdout)
if (!inkInstance) return false
// Only prepend +N for editors known to support it — notepad treats +42 as a
// filename to open. Test basename so /home/vim/bin/kak doesn't match 'vim'
// via the directory segment.
const useGotoLine = line && PLUS_N_EDITORS.test(basename(base))
inkInstance.enterAlternateScreen()
try {
const syncOpts: SpawnSyncOptions = { stdio: 'inherit' }
let result
if (process.platform === 'win32') {
// On Windows use shell: true so cmd.exe builtins like `start` resolve.
// shell: true joins args unquoted, so assemble the command string with
// explicit quoting ourselves (matching promptEditor.ts:74). spawnSync
// returns errors in .error rather than throwing.
const lineArg = useGotoLine ? `+${line} ` : ''
result = spawnSync(`${editor}${lineArg}"${filePath}"`, {
...syncOpts,
shell: true,
})
} else {
// POSIX: spawn directly (no shell), argv array is quote-safe.
const args = [
...editorArgs,
...(useGotoLine ? [`+${line}`, filePath] : [filePath]),
]
result = spawnSync(base, args, syncOpts)
}
if (result.error) {
logForDebugging(`editor spawn failed: ${result.error}`, {
level: 'error',
})
return false
}
return true
} finally {
inkInstance.exitAlternateScreen()
}
}
export const getExternalEditor = memoize((): string | undefined => {
// Prioritize environment variables
if (process.env.VISUAL?.trim()) {
return process.env.VISUAL.trim()
}
if (process.env.EDITOR?.trim()) {
return process.env.EDITOR.trim()
}
// `isCommandAvailable` breaks the claude process' stdin on Windows
// as a bandaid, we skip it
if (process.platform === 'win32') {
return 'start /wait notepad'
}
// Search for available editors in order of preference
const editors = ['code', 'vi', 'nano']
return editors.find(command => isCommandAvailable(command))
})
Loading...
举报
举报成功
我们将于2个工作日内通过站内信反馈结果给你!
请认真填写举报原因,尽可能描述详细。
请选择举报类型
取消
发送
误判申诉

此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。

如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。

取消
提交

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
编辑仓库简介
简介内容
主页
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/up/claude-code-source-code.git
git@gitee.com:up/claude-code-source-code.git
up
claude-code-source-code
claude-code-source-code
main
点此查找更多帮助

搜索帮助

评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册

AltStyle によって変換されたページ (->オリジナル) /