العمل داخل Cursor / Claude Code / Aider / Copilot
Cursor: غلاف الـ diff
لما بتـprompt LLM جوّه IDE — Cursor، Zed، IntelliJ AI Assistant، JetBrains AI — الموديل مش حر يدردش. محتاج يطلّع output الـ IDE يقدر يتحلّله ويطبّقه على طول على الـ buffer. شكل المخرج الصح هو unified diff ملفوف في code block.
تدفق الـ module ده:
Module 5 — هيكل واحد، 5 أغلفة مخرجات
Unified diff الـ IDE بيطبّقه على الـ buffer
SEARCH/REPLACE — نص بالظبط، مفيش أرقام سطور
خطّط، وافق، ونفّذ — ببوابة صلاحيات حقيقية
مفيش prompt أصلاً. الملف فوق الـ cursor هو الـ prompt
Conventional commit متولّد من الـ diff
دورة user-message → diff في Cursor:
الدورة الكاملة، والمكانين اللي ممكن تتكسر فيهم
System prompt قصير + طلب user مركّز بيوصّلك. ده الـ system prompt اللي بيخلّي الموديل يتصرف زي IDE-native pair:
You are an expert pair programmer working inside an IDE. The user shows you code; you respond with a unified diff (
---/+++/ hunk markers) only — no prose unless explicitly asked. Always preserve unrelated lines exactly.
دلوقتي رسالة الـ user بس الملف والتغيير المطلوب:
File:
src/utils/email.tsexport function isValidEmail(s: string): boolean { return s.includes("@") && s.includes("."); }Task: tighten the validation. Reject leading/trailing whitespace, require at least one char before "@", require a dot AFTER "@", and a TLD of at least 2 letters. Keep the same signature.
Claude Sonnet 4.5 رجّع:
--- src/utils/email.ts
+++ src/utils/email.ts
@@ -1,3 +1,11 @@
export function isValidEmail(s: string): boolean {
- return s.includes("@") && s.includes(".");
+ if (s !== s.trim()) return false;
+
+ const atIndex = s.indexOf("@");
+ if (atIndex <= 0) return false;
+
+ const domain = s.slice(atIndex + 1);
+ const lastDotIndex = domain.lastIndexOf(".");
+ if (lastDotIndex === -1) return false;
+
+ return domain.slice(lastDotIndex + 1).length >= 2;
}
Captured from Claude Sonnet 4.5 (claude-sonnet-4-5) on 2026-04-27. Re-runs may differ slightly. شوف ملاحظة دورة حياة الموديل في Module 1، الدرس الأول.
المنطق سليم. كل حالة في المهمة بتعدّي. والـ diff ده مش بيتطبّق. احفظه في ملف وشغّله:
$ git apply -p0 email.diff
error: corrupt patch at line 17
$ patch -p0 < email.diff
patch: **** malformed patch at line 16: }
اقرا الـ hunk header: @@ -1,3 +1,11 @@. بيقول إن البديل 11 سطر. عُدّ جسم الـ hunk — سطر context واحد، 10 سطور +، والقفلة } — تلاقيهم 12. git apply و patch الاتنين بيتأكدوا من العدد ده قبل ما يلمسوا ملفك، والاتنين بيرفضوا.
دي أهم حاجة في الدرس، فمتعديش عليها بسرعة. الـ unified diff فيه نوعين من الصح، وبيفشلوا بشكل مستقل:
| الطبقة | معناها | بتفشل إزاي | مين بيمسكها |
|---|---|---|---|
| دلالية (Semantic) | الكود الجديد بيعمل الصح؟ | منطق غلط، حالة حدّية غلط | إنت، في الـ review |
| بنيوية (Structural) | الـ offsets وعدد السطور متسقين؟ | عدد سطور غلط بواحد، @@ header غلط | أداة الـ patch، قبل ما تكتب أي حاجة |
الموديل اللي شاطر في الأولى مش بالضرورة شاطر في التانية، لأن التانية حساب على مخرجه هو — لازم يعُدّ السطور اللي هيكتبها قبل ما يكتبها. ده بالظبط أضعف حاجة عند الـ language models، وهو غير مرئي وإنت بتقرا لأن عينك بتقرا الكود وبتتخطى سطر الـ @@.
غيّر +1,11 لـ +1,12 وهيتطبّق نضيف. مفيش حاجة تانية محتاجة تتحرّك.
تعمل إيه، بالترتيب:
- سيب الأداة تعُدّ. Cursor ومعظم مساعدات الـ IDE بيطبّقوا تعديلات الموديل عن طريق fuzzy matcher بيعيد التمركز على الـ context حواليه بدل ما يثق في الـ header — فالـ header المكسور غالباً بيعيش جوه الـ IDE وبيفشل أول ما تصدّر الـ diff، أو تلزّقه في PR، أو تمرّره لـ
git apply. الغلاف اللي هتسلّمه لأداة تانية هو اللي لازم يكون مضبوط. - اطلب functions كاملة، مش hunks، لما التغيير صغير.
Output the complete rewritten function in a single code blockمفيهاش offsets تتغلط فيها. - تحقّق قبل ما تثق.
git apply --checkفوري وبيرجّع كود غير صفري على أي patch مكسور:
git apply --check my-change.diff && echo "applies cleanly"
ضيف السطر ده لدورتك وهتبطّل الأخطاء البنيوية توصل للـ branch بتاعك.
من ناحية الدلالة المخرج نضيف: مفيش prose تشيله، مفيش شرح تتجاهله، مفيش implementations بديلة. ده اللي اشتراه قيد الـ format. هو بس ما اشتراش diff بيتطبّق.
الـ system prompt بيعمل 4 حاجات في نفس الوقت:
| العبارة | الأثر |
|---|---|
| "expert pair programmer" | بيظبط الـ persona ناحية صوت مهندس senior |
| "working inside an IDE" | بيأطّر المخرج للاستهلاك بأداة |
| "unified diff only" | بيقفل format المخرج |
| "preserve unrelated lines exactly" | بيمنع الموديل من تهريب تغييرات formatting |
الـ constraint الأخير ده مهم أكتر مما يبان. من غيره، الموديل غالباً "بيحسّن" الـ indentation، بيغيّر single quotes لـ double quotes، أو بيضيف trailing newline ناقصة. كل واحدة من دول بتعمل ضوضاء في الـ diff وفي git history. الـ constraint بيجبر الـ diff إنه يضم بس التغيير اللي عايزه.
امتداد مفيد: اطلب من الموديل يضيف الـ test في نفس الـ diff:
Task: tighten the validation as described, AND add a unit test in
src/utils/email.test.tscovering the new rules. Both changes in the same diff.
غلاف الـ diff بيتعامل مع تغييرات multi-file بشكل طبيعي — كل ملف بياخد --- / +++ pair. الـ IDE بيطبّق كل الـ hunks مع بعض، وبتجيب تغيير atomic.
لما الـ diff يرجع غلط، الحل نادراً ما يكون "اشتغل تاني بـ prompt أحسن." عادة "وريني اللي جربته، وطبّق الـ patch اللي بوصفه." Cursor، Zed، وأدوات مشابهة بتسمح بده من واجهة الـ chat. نمط المحادثة: الموديل بيقترح diff → بتطبّقه ذهنياً → بتصحّح سطر واحد → الموديل بيعيد كتابة الـ diff. 3 turns، تغيير واحد متـmerge.
الأربع envelopes اللي هتقابلهم في الـ module ده، جنب بعض:
Envelopes Prompts على شكل IDE
Cursor / Zed
- تغيير atomic على ملفات
- قابل للمراجعة hunk by hunk
- انجراف line numbers بيكسر diffs قديمة
- الموديل بيتغرى يعيد تنسيق سطور مش متعلقة
Aider
- بيعدّي تعديلات حواليه
- الـ apply بيفشل بصوت عالي لو misread
- block لكل تعديل منطقي وإلا الـ rollback شكله وحش
- مفصّل لتغيير سطر واحد
Claude Code
- بوابة plan-then-go بتمنع scope creep
- الـ agent بيعمل self-check للـ invariants
- محتاج context طويل
- نمط الفشل هو تعديل في الهدوء من غير 'go'
Copilot / Tabnine
- مفيش احتكاك في الـ flow
- بيتحسّن بـ comments فوق الـ cursor
- مفيش control surface تاني غير الملف
- عام لو اسم الـ function غامض
التالي: format SEARCH/REPLACE blocks اللي بيستخدمه Aider. :::
سجّل الدخول للتقييم