LevelUpWith

Explore / Cursor for Real Software Work: From VS Code to Agents / Lesson 2

Lesson 2: Tab Completion That Earns Its Keep

Learn how Cursor's Tab completion suggests multi-line edits and cursor jumps, and when to accept part of a suggestion, all of it, or none.

Free to read, no account needed. Part of Cursor for Real Software Work: From VS Code to Agents.

By the end of this level you'll be able to

  • Accept a whole Tab suggestion or only part of it, and dismiss suggestions you don't want, while doing a refactor in the practice repo
  • Spot when a Tab suggestion is plausible but wrong, such as a made-up API or a missed edge case, and reject it
  • Change or snooze Tab completion for specific file types where it gets in the way, then check the setting persists

Why Tab is different from the autocomplete you know

In VS Code, autocomplete finishes the word you are typing. Cursor's Tab tries to guess your next edit. That edit might be several lines long, it might change code you already wrote rather than add new code, and it might sit somewhere other than where your cursor is now. In practice it does three things:

  • Multi-line edits. It suggests changes across a block. It can also add a missing import or make matching changes in related code.
  • Jumps inside the file. After you accept a suggestion, Tab may predict where you will edit next. Press Tab again and the editor moves you there.
  • Edits in other files. If a change in one file means another file needs updating, a small preview window appears at the bottom of the editor.

A good way to think of it: Tab is a pair partner who has seen your last few keystrokes and says "you're about to do the same thing on line 40, aren't you?" Often they're right. Sometimes they're confidently wrong. The skill is telling which, in under a second.

The three keys you need

Suggestions show up as grey text ahead of your cursor (or as a highlighted diff when they change existing code). Then:

You want to... Windows / Linux macOS
Accept the whole suggestion Tab Tab
Accept the next word only Ctrl + → Cmd + →
Reject it Esc, or just keep typing Esc, or keep typing

Two things catch people out:

  • Partial accept takes over a key you already use. In VS Code, Ctrl + → moves you one word along. While a suggestion is showing, it accepts a word of the suggestion instead. If that annoys you, remap it. Search for Accept Cursor Tab Suggestions in Keyboard Shortcuts to change the full-accept key too.
  • You don't have to dismiss anything. If the suggestion is wrong, keep typing and it disappears. Esc is for when you want it gone now.

Walkthrough: a rename refactor in the practice repo

Open src/cart.ts in the practice repository. It has a function with an unhelpful parameter name:

// src/cart.ts (before)
export function total(xs: CartItem[]): number {
  let sum = 0;
  for (const x of xs) {        // 'xs' is used again here
    sum += x.price * x.qty;
  }
  return xs.length ? sum : 0;  // ...and here
}
  1. Change xs to items in the signature by hand.
  2. Wait a moment. Tab should offer to change the other two xs as well, either as one diff or one at a time with a jump.
  3. Press Tab to accept. If a jump marker appears, press Tab again and you land on the next spot.
  4. Now change x to item in the loop header. This time accept only part of the suggestion. If Tab offers item.price * item.qty; plus a comment you don't want, press Ctrl + → until you've taken the code, then Esc.
// src/cart.ts (after)
export function total(items: CartItem[]): number {
  let sum = 0;
  for (const item of items) {
    sum += item.price * item.qty;
  }
  return items.length ? sum : 0;
}

Check: run npm test (the repo has a cart.test.ts). It should pass exactly as before, because a rename shouldn't change behaviour.

Plausible but wrong: the suggestions to reject

Tab writes code that looks like your code, and that's exactly why a wrong suggestion slips past. Now add an average function under total and type the signature:

export function averagePrice(items: CartItem[]): number {
  // Tab may suggest something like:
  return items.reduce((a, i) => a + i.price, 0) / items.length;
}

It reads fine, but with an empty cart it returns NaN (0 / 0). Your total function handled the empty case, and this suggestion doesn't. Reject it and write the guard yourself, or accept it and fix it right away:

export function averagePrice(items: CartItem[]): number {
  if (items.length === 0) return 0;  // the edge case Tab skipped
  return items.reduce((a, i) => a + i.price, 0) / items.length;
}

The other common failure is a made-up API: a method that sounds right but isn't real, such as items.sumBy('price') on a plain array, or an option your library version doesn't have. A quick test: would I bet a coffee this method exists? If not, reject it, or accept it and watch for a red squiggle from TypeScript. The type checker is your cheapest second opinion.

Rule of thumb from production use: accept freely when the edit is mechanical and repeats something you just did (renames, matching changes, imports). Slow down when it brings in new logic or new APIs. That's where it guesses.

Turning Tab down where it gets in the way

In some files Tab is mostly noise. Markdown, JSON and commit messages are the usual offenders. Click the Tab status indicator in the bottom-right corner of the window. It gives you:

  • Snooze: turns Tab off for a length of time you choose, for example while you write a design doc.
  • Disable globally: turns it off everywhere until you turn it back on.
  • Disable for certain file types: turns it off for, say, Markdown, and leaves it on for everything else.

More options live under Cursor Settings > Tab.

Task: disable Tab for Markdown, open README.md and type a sentence. No grey text should appear. Now close and reopen Cursor, open the README again and check that suggestions are still off. Then open cart.ts and check they still work there.

If you want to see where the setting ended up, open your user settings.json. Recent builds store the per-language list under an internal key that looks like this:

{
  // Language IDs where Tab is off. The key name is internal and may change.
  "cursor.cpp.disabledLanguages": ["markdown"]
}

Gotcha: users have reported that this list doesn't apply to new unsaved files until you save them, so check the setting on a saved file.

Key takeaways

  • Tab predicts your next edit: multi-line changes, jumps within the file, and changes that span files.
  • Tab accepts all of it, Ctrl/Cmd + → accepts word by word, and Esc or carrying on typing rejects it.
  • Trust it with mechanical, repeated edits. Look closely at new logic, edge cases and APIs you don't recognise.
  • The type checker and your tests catch wrong suggestions cheaply. Run them after you accept.
  • Use the status-bar indicator to snooze Tab or turn it off per file type, and check that the setting is still there after a restart.

A 6-question knowledge check follows this lesson in the app, free and without an account.

Keep going: levels 3 and 4 are free

Create a free account to open the next two levels, save your progress and pick up where you left off. No card needed.

Next: Level 3, Inline Edits on a Selection.

Create a free account →See the whole course

More like this

  • GitHub Copilot (GH-300) Exam Prep

    Learn GitHub Copilot hands-on in the editor, in the CLI and on github.com, and work through every skill in the GH-300 study guide (skills measured as of August…

    Exam prep · GH-300 · Software & Engineering · Capable · 18 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 3, Mobile Apps, Games and Growth

    Turn your first live app into a real product. Learn to choose between web and app store apps, publish a browser game, take payments safely, run and monitor a l…

    Course · Software · Software & Engineering · Capable · 24 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 2, Online, Secure and AI-Powered

    Take one small app from your GitHub repository to a public web address. You will host it on Vercel and give it a Supabase database, sign-in and file storage, w…

    Course · Software · Software & Engineering · Capable · 16 levels · 4 free · Professionally curated by levelupwith.com

  • Scaling Apps Beyond the Chat Window: Part 1, From Prompt to Project

    Move an app you built in an AI chat onto your own computer and work on it step by step with a coding agent. Save your work with Git, keep secrets out of your c…

    Course · Software · Software & Engineering · Capable · 19 levels · 4 free · Professionally curated by levelupwith.com

  • Right Chip, Right Job: CPUs, GPUs, TPUs and Beyond

    Profile a workload, place it on a roofline and pick the processor that actually suits it, whether CPU, GPU, TPU, ASIC, inference chip, NPU, FPGA or DPU. You wi…

    Beyond the Obvious · Software & Engineering · Expert · 61 levels · 4 free · Professionally curated by levelupwith.com

  • Build Your First Website with HTML and CSS

    Start from a blank file and build a real, accessible personal or small-business website that works on phones. Each level adds to the same site, covering semant…

    Course · Software · Software & Engineering · Capable · 18 levels · 4 free · Professionally curated by levelupwith.com