العمل داخل Cursor / Claude Code / Aider / Copilot

Cursor: غلاف الـ diff

4 دقيقة للقراءة

لما بتـprompt LLM جوّه IDE — Cursor، Zed، IntelliJ AI Assistant، JetBrains AI — الموديل مش حر يدردش. محتاج يطلّع output الـ IDE يقدر يتحلّله ويطبّقه على طول على الـ buffer. شكل المخرج الصح هو unified diff ملفوف في code block.

تدفق الـ module ده:

Module 5 — هيكل واحد، 5 أغلفة مخرجات

1. Cursor

Unified diff الـ IDE بيطبّقه على الـ buffer

2. Aider

SEARCH/REPLACE — نص بالظبط، مفيش أرقام سطور

3. Claude Code

خطّط، وافق، ونفّذ — ببوابة صلاحيات حقيقية

4. Copilot

مفيش prompt أصلاً. الملف فوق الـ cursor هو الـ prompt

5. رسالة الـ commit

Conventional commit متولّد من الـ diff

دورة user-message → diff في Cursor:

الدورة الكاملة، والمكانين اللي ممكن تتكسر فيهم

بيقفل الغلافبيقدّم المهمةSystem prompt'Unified diff only. Preserve un…رسالة المستخدمالملف، وبعدين طلب التغييرالموديل بيطلّع diffعناوين ---/+++، الـ @@ hunk hea…إنتفحص دلاليالكود الجديد بيعمل الصح؟ ده بتم…الأدواتفحص بنيويأعداد سطور الـ @@ متطابقة مع جس…متطبّق على الـ bufferالفحصين عدّوا، فالتغيير ذرّي وق…

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.ts

export 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 وهيتطبّق نضيف. مفيش حاجة تانية محتاجة تتحرّك.

تعمل إيه، بالترتيب:

  1. سيب الأداة تعُدّ. Cursor ومعظم مساعدات الـ IDE بيطبّقوا تعديلات الموديل عن طريق fuzzy matcher بيعيد التمركز على الـ context حواليه بدل ما يثق في الـ header — فالـ header المكسور غالباً بيعيش جوه الـ IDE وبيفشل أول ما تصدّر الـ diff، أو تلزّقه في PR، أو تمرّره لـ git apply. الغلاف اللي هتسلّمه لأداة تانية هو اللي لازم يكون مضبوط.
  2. اطلب functions كاملة، مش hunks، لما التغيير صغير. Output the complete rewritten function in a single code block مفيهاش offsets تتغلط فيها.
  3. تحقّق قبل ما تثق. 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.ts covering 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

Diff

Cursor / Zed

شكل الـ inputملف + مهمة في chat
شكل الـ outputUnified diff (---/+++)
خطوة الـ applyالـ IDE بيعمل patch للـ buffer
قوي فيInline edits، hunks في ملفات كتير
المزايا
  • تغيير atomic على ملفات
  • قابل للمراجعة hunk by hunk
العيوب
  • انجراف line numbers بيكسر diffs قديمة
  • الموديل بيتغرى يعيد تنسيق سطور مش متعلقة
SEARCH/REPLACE

Aider

شكل الـ inputسياق الـ repo + مهمة
شكل الـ output&#x3C;&#x3C;&#x3C; SEARCH / === / REPLACE >>>
خطوة الـ applyAider بيطابق النص بالظبط
قوي فيSessions طويلة، أمان من انجراف السطور
المزايا
  • بيعدّي تعديلات حواليه
  • الـ apply بيفشل بصوت عالي لو misread
العيوب
  • block لكل تعديل منطقي وإلا الـ rollback شكله وحش
  • مفصّل لتغيير سطر واحد
Plan + execute

Claude Code

شكل الـ inputمهمة محادثة + repo
شكل الـ outputPlan → tool calls → diff
خطوة الـ applyالـ agent بيعدّل ويشغّل tests
قوي فيFeatures متعددة الخطوات، invariants
المزايا
  • بوابة plan-then-go بتمنع scope creep
  • الـ agent بيعمل self-check للـ invariants
العيوب
  • محتاج context طويل
  • نمط الفشل هو تعديل في الهدوء من غير 'go'
Completion

Copilot / Tabnine

شكل الـ inputالملف فوق الـ cursor
شكل الـ outputCompletion inline
خطوة الـ applyTab للقبول
قوي فيBodies بـ signature كويسة
المزايا
  • مفيش احتكاك في الـ flow
  • بيتحسّن بـ comments فوق الـ cursor
العيوب
  • مفيش control surface تاني غير الملف
  • عام لو اسم الـ function غامض

التالي: format SEARCH/REPLACE blocks اللي بيستخدمه Aider. :::

اختبار

الوحدة 5: Prompts الأدوات و الـ IDE

خذ الاختبار
هل كان هذا الدرس مفيدًا؟

سجّل الدخول للتقييم