開源 AI 程式碼編輯器
Web 版, Insiders 版, 或 其他平臺
import { For, createSignal, createMemo } from "solid-js";
import { useNavigate, useParams } from "@tanstack/solid-router";
import { getEmailsForMailbox } from "~/data/emails";
import { MailListItem } from "~/components/MailListItem";
export function MailList() {
const params = useParams({ strict: false }) as {
mailbox?: string;
id?: string;
};
const navigate = useNavigate();
const [query, setQuery] = createSignal("");
const mailbox = () => params.mailbox || "inbox";
const list = createMemo(() => {
const q = query().toLowerCase();
return getEmailsForMailbox(mailbox()).filter(
(e) =>
!q ||
e.subject.toLowerCase().includes(q) ||
e.snippet.toLowerCase().includes(q)
);
});
function open(id: string) {
navigate({
to: "/mail/$mailbox/$id",
params: { mailbox: mailbox(), id },
search: (prev) => prev,
});
}
return (
<For each={list()}>
{(e) => (
<div
role="listitem"
tabindex={0}
onClick={() => open(e.id)}
onKeyDown={(ev) => ev.key === "Enter" && open(e.id)}
class="mail-item"
data-selected={params.id === e.id ? "true" : undefined}
aria-selected={params.id === e.id ? "true" : undefined}
>
<div>
<div class="mail-item-subject truncate">{e.subject}</div>
<div class="mail-item-snippet truncate">{e.snippet}</div>
</div>
<time
class="text-xs muted"
datetime={e.date}
title={new Date(e.date).toLocaleString()}
>
{new Date(e.date).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
})}
</time>
</div>
<MailListItem
email={e}
isSelected={params.id === e.id}
onOpen={open}
/>
)}
</For>
);
}
import type { Email } from "~/types";
interface MailListItemProps {
email: Email;
isSelected: boolean;
onOpen: (id: string) => void;
}
export function MailListItem(props: MailListItemProps) {
return (
<div
role="listitem"
tabindex={0}
onClick={() => props.onOpen(props.email.id)}
onKeyDown={(ev) => ev.key === "Enter" && props.onOpen(props.email.id)}
class="mail-item"
data-selected={props.isSelected ? "true" : undefined}
aria-selected={props.isSelected ? "true" : undefined}
>
<div>
<div class="mail-item-subject truncate">{props.email.subject}</div>
<div class="mail-item-snippet truncate">{props.email.snippet}</div>
</div>
<time
class="text-xs muted"
datetime={props.email.date}
title={new Date(props.email.date).toLocaleString()}
>
{new Date(props.email.date).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
})}
</time>
</div>
);
- 建立新的
MailListItem 元件,用於處理單個郵件列表項的渲染 - 將郵件項的 JSX 和邏輯從
MailList 提取到新的MailListItem 元件中 - 更新
MailList 以使用新的MailListItem 元件中 - 構建專案以驗證更改是否正確編譯
- 測試應用程式以確保功能保持不變
- 建立了一個可重用的元件,用於渲染單個郵件列表項
- 接受
email ,isSelected 和onSelect props - 維護所有可訪問性功能(ARIA 角色、鍵盤導航)
- 保留樣式和互動行為
- 透過刪除內聯郵件項渲染邏輯得到簡化
- 現在使用
MailListItem 元件並傳遞乾淨的 props - 降低了元件複雜性並提高了可讀性
- ✅ 構建成功
- ✅ 所有功能正常工作(過濾、選擇、導航)
- ✅ 鍵盤可訪問性得以保留(Enter 鍵導航)
- ✅ 視覺化選擇狀態工作正常
為任何團隊提供的任何模型
從多個開箱即用的模型中進行選擇,或攜帶您自己的金鑰以訪問來自您首選模型和託管提供商的模型。
您程式碼庫的專家
您的程式碼庫已在本地和遠端建立索引,以便理解哪些內容相關,從而實現快速、上下文感知的互動。
以團隊工作方式工作的 AI
使用自定義代理、自定義指令和可重用提示檔案來個性化互動,以適應您的工作流程和工具。
---
description: 'Generate compact responses, focusing on brevity and clarity.'
tools: ['search', 'fetch', 'githubRepo', 'usages', 'vscodeAPI', 'problems', 'changes', 'testFailure', 'todos']
---
You are a chat mode that provides extremely concise and clear responses.
Your replies should be brief, to the point, and free of unnecessary details.
Focus on delivering the essential information in a straightforward manner.
When responding, you must adhere to the following guidelines:
- Use short sentences and simple language.
- Prioritize clarity over completeness.
- Do not provide explanations or justifications unless explicitly asked.
- Do not provide any updates as you are working on the task –– only respond when the task is complete.
代理模式
處理複雜的、多步驟的任務。代理模式會讀取您的程式碼庫、建議跨檔案的編輯、執行終端命令,並響應編譯或測試失敗——所有這些都在一個迴圈中,直到工作完成。透過 VS Code 擴充套件和模型上下文協議 (MCP) 伺服器,進一步完善代理模式以適應您團隊的工作流程。
使用代理模式構建package http
import (
"io"
"log/slog"
"mime/multipart"
"net/http"
"strings"
)
type BatchItemResult struct {
Name string `json:"name"`
Metadata *struct {
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Bytes int `json:"bytes"`
} `json:"metadata,omitempty"`
Error string `json:"error,omitempty"`
}
type BatchResponse struct {
Results []*BatchItemResult `json:"results"`
Count int `json:"count"`
Success int `json:"success"`
Failed int `json:"failed"`
}
// handleProcessBatch processes multiple uploaded images (multipart/form-data) under the field name "files".
// It returns metadata for each image or an error per item without failing the whole batch unless the request is malformed.
func (s *Server) handleProcessBatch(w http.ResponseWriter, r *http.Request) {
// Enforce max body size overall.
r.Body = http.MaxBytesReader(w, r.Body, s.cfg.MaxUploadBytes)
if ct := r.Header.Get("Content-Type"); !strings.HasPrefix(ct, "multipart/form-data") {
s.writeJSON(w, http.StatusBadRequest, map[string]string{"error": "content type must be multipart/form-data"})
return
}
if err := r.ParseMultipartForm(s.cfg.MaxUploadBytes); err != nil {
status := http.StatusBadRequest
if strings.Contains(err.Error(), "request body too large") {
status = http.StatusRequestEntityTooLarge
}
s.writeJSON(w, status, map[string]string{"error": "invalid multipart form: " + err.Error()})
return
}
// Accept files under the key "files". If absent, attempt to fallback to any file parts.
var fileHeaders []*multipart.FileHeader
if r.MultipartForm != nil && len(r.MultipartForm.File["files"]) > 0 {
fileHeaders = r.MultipartForm.File["files"]
} else if r.MultipartForm != nil {
// Fallback: gather all files across keys.
for _, fhs := range r.MultipartForm.File {
fileHeaders = append(fileHeaders, fhs...)
}
}
if len(fileHeaders) == 0 {
s.writeJSON(w, http.StatusBadRequest, map[string]string{"error": "no files provided (expect key 'files')"})
return
}
resp := &BatchResponse{Results: make([]*BatchItemResult, 0, len(fileHeaders))}
for _, fh := range fileHeaders {
item := &BatchItemResult{Name: fh.Filename}
f, err := fh.Open()
if err != nil {
item.Error = "open file: " + err.Error()
resp.Results = append(resp.Results, item)
resp.Failed++
continue
}
data, err := io.ReadAll(f)
_ = f.Close()
if err != nil {
item.Error = "read file: " + err.Error()
resp.Results = append(resp.Results, item)
resp.Failed++
continue
}
meta, err := s.proc.ExtractMetadata(data)
if err != nil {
item.Error = err.Error()
resp.Results = append(resp.Results, item)
resp.Failed++
continue
}
// Copy into anonymous struct to decouple from internal type if it changes.
item.Metadata = &struct {
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Bytes int `json:"bytes"`
}{Format: meta.Format, Width: meta.Width, Height: meta.Height, Bytes: meta.Bytes}
resp.Results = append(resp.Results, item)
resp.Success++
}
resp.Count = len(resp.Results)
s.log.LogAttrs(r.Context(), slog.LevelInfo, "batch processed", slog.Int("count", resp.Count), slog.Int("success", resp.Success), slog.Int("failed", resp.Failed))
s.writeJSON(w, http.StatusOK, resp)
}
建立一個待辦事項列表
我從建立待辦事項列表開始,管理任務,例如讀取現有伺服器和處理器程式碼,設計批處理端點合約,並在一個新檔案中實現一個帶有處理程式的邏輯。我想將處理程式連線到伺服器路由,也許為批處理端點新增一個最小的測試,儘管那是可選的。我也會計劃稍後執行測試並構建所有內容。我們開始吧!改進檔案處理...
我可能會修改 server.go,但他們要求一個新檔案。因此,我需要建立一個路由,我們稱之為 /process/batch。我將強制執行最大請求體大小,並確保內容型別是 multipart/form-data。接下來,我將解析表單並遍歷 form.File["files"]。 對於每個 FileHeader,我將開啟它並讀取位元組,然後呼叫 ExtractMetadata 來收集結果。最後,我將返回一個帶有結果的結構化 JSON 響應,並處理無檔案和最大批次限制的邊緣情況。 我認為這可能不是絕對必要的,但我正在考慮透過使用 sync.WaitGroup 來順序處理每個檔案,同時限制併發性來做一些小的改進。這將使初始提交更簡單。我需要新增程式碼檔案並匯入 internal/image 引用別名。 接下來,我將檢視 tests/image_processor_test.go 中現有的測試以瞭解風格,並確定我是否應該為批處理處理程式建立一個新的測試檔案。我將閱讀該檔案,然後更新待辦事項狀態,將任務一和二標記為已完成。準備進行 HTTP 測試
我需要執行一個 HTTP 測試,但我注意到當前的測試包在 'tests' 中,而不是在主模組中。為了進行 HTTP 測試,我需要設定一些東西,比如 config、processor、logger 和 server,以及傳送一個 multipart 請求。我的下一步是檢查 config.go 中的配置,以瞭解我需要包含哪些必需的欄位。讓我們深入瞭解一下!管理更新和補丁
我需要使用 manage_todo_list 來保持一切井井有條,確保我沒有遺漏任何任務。完成後,我就可以應用補丁了。這涉及新增一個新檔案並修改 server.go。我想確保在這個過程中一切都清晰準確,以避免任何錯誤。讓我們繼續前進!實施更新和測試
我將設計合約標記為完成,然後我需要實施更新。我將繼續管理待辦事項列表並應用補丁以新增一個檔案並更新 server.go。看起來我可能需要在 server.go 中新增一個 POST /process/batch 的路由,並在 internal/http/batch.go 中實現一個新檔案。編寫程式碼後,我將新增一個測試檔案,使用 go test 執行測試,並使用 run_in_terminal 命令。讓我們開始吧!-
server.go : 註冊了新路由 POST /process/batch。 batch.go : 新的處理程式 handleProcessBatch-
- 接受 multipart/form-data。
- 讀取 files 鍵下的多個檔案(如果 files 缺失,則回退到任何檔案部分)。
- 為每個檔案返回成功/錯誤,而不會使整個批次失敗。
- 聚合計數:count、success、failed。
-
batch_endpoint_test.go : 測試正常路徑(1 個有效 + 1 個無效檔案)和缺少檔案錯誤情況。
- 為每個批次新增可配置的最大檔案數(例如,透過配置)。
- 使用受限記憶體的流處理(process + discard)以處理非常大的影像。
- 使用工作池和上下文取消的並行處理(可選)。
- 在解碼前新增每檔案的尺寸驗證。
- 支援基於 JSON 的批處理(URL 或 base64),以支援非 multipart 客戶端。
下一個編輯建議
當您編碼時,VS Code 會預測您的下一步操作。使用 Tab 鍵直接在編輯器中接受 AI 驅動的建議。它會根據您正在進行的編輯智慧推薦要更改的內容——以及在哪裡更改。
使用 AI 驅動的建議進行編碼import numpy as np
import pandas as pd
iris_data = pd.read_csv("iris_dataset.csv")
def describe(species: str) -> pd.Series:
7
subset = data[data["species"] == species]
subset = iris_data[iris_data["species"] == species]
if subset.empty:
raise ValueError(f"{species} missing from sample")
return subset[["petal", "sepal"]].agg(["mean", "std"]).loc["mean"]
def summary():
13
for species in np.sort(data["species"].unique()):
for species in np.sort(iris_data["species"].unique()):
try:
stats = describe(species)
except ValueError:
print(f"{species}: no records")
continue
print(f"{species}: petal={stats['petal']:.2f} sepal={stats['sepal']:.2f}")
if __name__ == "__main__":
summary()
使用擴充套件進行編碼
使用擴充套件和模型上下文協議 (MCP) 伺服器來自定義 VS Code 中的 AI 功能以在聊天中使用。或者,構建您自己的擴充套件以支援您團隊的獨特場景。
用任何語言編碼
VS Code 支援幾乎所有主要的程式語言。一些語言(如 JavaScript、TypeScript、CSS 和 HTML)隨附在編輯器中,但其他語言的擴充套件可以在 VS Code 市場中找到。

JavaScript
TypeScript
Python
C#
C++
HTML
Java
JSON
PHP
Markdown
Powershell
YAML隨時隨地編寫程式碼
無論您是連線到雲、遠端儲存庫,還是在瀏覽器中使用 VS Code for the Web (vscode.dev),都可以在最有效率的地方編寫程式碼。
內建原始碼管理開箱即用地為您提供 Git 支援。許多其他原始碼管理提供商可透過擴充套件獲得。
GitHub Codespaces 為任何活動提供雲驅動的開發環境——無論是長期專案,還是像審查拉取請求這樣的短期任務。
透過豐富功能進行編碼
編輯器還有更多內容。無論是使用內建功能還是豐富的擴充套件,總有適合每個人的東西。