# Lecture 3 – Development Environment and Tools

### Overview

Every professional developer works inside a development environment — a curated collection of tools that transforms a blank terminal into a productive workspace. This lecture examines what that environment actually consists of, how its pieces work together, and how to set one up that genuinely accelerates your thinking.

The lecture covers two parallel tracks: the **terminal-based workflow** (Vim + language-specific CLI tools) and the **IDE-based workflow** (VS Code + extensions + language servers). Rather than picking a side, it argues for developing fluency in both, since the right tool depends entirely on the context you're working in.

#### Key Takeaways

* A development environment is not a single program — it's a **layered stack** of text editing, language intelligence, linting, formatting, AI assistance, and extensions.
* **Vim's core idea** is that its interface is itself a composable programming language — keystrokes are verbs and nouns that combine to form editing expressions.
* **Modal editing** separates concerns: Normal mode for navigation, Insert mode for typing, Visual mode for selection. Spending time in Normal mode (not Insert) is what makes Vim fast.
* **Language servers** implement a standard protocol (LSP) that gives any editor the same deep, language-aware intelligence: autocomplete, jump-to-definition, find references, inline errors.
* **AI coding tools** exist on a spectrum from passive autocomplete, to inline chat edits, to fully autonomous coding agents — each with a different mental model of interaction.
* **IDE extensions** for remote development, dev containers, and collaborative editing can transform VS Code into a full cloud development environment.
* **Vim mode is available almost everywhere** — VS Code, Zsh, JetBrains IDEs, Claude Code — you don't have to use Vim itself to benefit from its movement model.

***

### Core Concepts

#### The Development Environment Stack

A complete development environment is not just "an editor". It's a layered set of concerns:

| Layer                     | What it does                     | Examples                               |
| ------------------------- | -------------------------------- | -------------------------------------- |
| **Text editing**          | Navigate and modify code         | Vim, VS Code, Emacs                    |
| **Language intelligence** | Understand code semantics        | Language servers (LSP), Pylance, gopls |
| **Code quality**          | Catch errors before running      | Linters (Ruff), type checkers (Mypy)   |
| **AI assistance**         | Accelerate writing and reasoning | GitHub Copilot, Cursor, Claude Code    |
| **Extensions**            | Add specialized functionality    | Remote SSH, Dev Containers, Live Share |
| **Terminal layer**        | Glue everything together         | tmux, Zsh, shell scripts               |

These layers are **complementary, not competing**. A terminal-based developer uses Vim for editing, a language server CLI for intelligence, `ruff` for linting, and `tmux` to orchestrate it all. An IDE-based developer gets most of these from a single GUI application.

The key advice: **develop basic familiarity with both approaches, master at least one**. On a headless remote server with no GUI, terminal tools are your only option. In a collaborative team environment on a rich codebase, a GUI IDE often wins on out-of-the-box productivity.

***

#### Vim: The Philosophy

Vim's foundational idea is deceptively simple: **the editor interface is a programming language**.

In most editors, editing is a sequence of:

1. Move mouse to location
2. Click
3. Type
4. Repeat

In Vim, editing is a sequence of **composable commands**:

1. Type a verb (`d` = delete, `c` = change, `y` = yank/copy)
2. Type a noun or motion (`w` = word, `$` = end of line, `i(` = inside parentheses)
3. The combination executes

This means `d3w` deletes three words. `ci"` changes the content inside the nearest quotes. `y$` yanks from cursor to end of line. Once you internalize the grammar, you stop thinking about *how to edit* and start thinking only about *what to edit* — the mechanics disappear.

> Vim avoids the mouse because it breaks flow. It avoids arrow keys because they require moving your hands off the home row. The result, once learned, feels like editing at the speed of thought.

***

#### Modal Editing

Vim is a **modal editor** — the same keystrokes do different things depending on the current mode. This is the single biggest conceptual hurdle for beginners, and the single biggest source of Vim's power.

| Mode             | How to enter          | What keys do                            |
| ---------------- | --------------------- | --------------------------------------- |
| **Normal**       | `<ESC>` from anywhere | Navigation and editing commands         |
| **Insert**       | `i`, `a`, `o`, `O`    | Type text as in any editor              |
| **Replace**      | `R`                   | Overwrite characters as you type        |
| **Visual**       | `v`                   | Select characters                       |
| **Visual Line**  | `V`                   | Select whole lines                      |
| **Visual Block** | `Ctrl-v`              | Select a rectangular block              |
| **Command-line** | `:`                   | Run Ex commands (`:w`, `:q`, `:%s/...`) |

The critical habit: **spend most of your time in Normal mode**, not Insert mode. Most beginners enter Insert mode immediately and stay there — they're essentially using Vim as a slow, confusing version of Notepad. The power comes from mastering Normal-mode movement and treating Insert mode as a brief visit.

***

#### Vim Movement: Nouns

Vim movements are called **nouns** — they refer to chunks of text that editing verbs will act on.

**Basic navigation:**

| Key             | Movement                             |
| --------------- | ------------------------------------ |
| `h` `j` `k` `l` | Left, down, up, right                |
| `w`             | Forward one word                     |
| `b`             | Backward one word                    |
| `e`             | End of current/next word             |
| `0`             | Beginning of line                    |
| `^`             | First non-blank character of line    |
| `$`             | End of line                          |
| `gg`            | Beginning of file                    |
| `G`             | End of file                          |
| `{number}G`     | Jump to line number                  |
| `Ctrl-u`        | Scroll up half a screen              |
| `Ctrl-d`        | Scroll down half a screen            |
| `H`             | Top of visible screen                |
| `M`             | Middle of visible screen             |
| `L`             | Bottom of visible screen             |
| `%`             | Jump to matching bracket/paren/brace |

**Search and find on a line:**

| Key       | Movement                                    |
| --------- | ------------------------------------------- |
| `f{char}` | Jump forward to character                   |
| `t{char}` | Jump forward *until* character (one before) |
| `F{char}` | Jump backward to character                  |
| `T{char}` | Jump backward *until* character             |
| `;`       | Repeat last `f`/`t`/`F`/`T`                 |
| `,`       | Repeat last in opposite direction           |

**File-wide search:**

| Key          | Movement                    |
| ------------ | --------------------------- |
| `/{pattern}` | Search forward for pattern  |
| `?{pattern}` | Search backward for pattern |
| `n`          | Next match                  |
| `N`          | Previous match              |

***

#### Vim Editing: Verbs

Editing commands are **verbs** that act on nouns (motions):

| Verb        | Action                                      |
| ----------- | ------------------------------------------- |
| `d{motion}` | Delete (also copies to buffer)              |
| `c{motion}` | Change (delete + enter Insert mode)         |
| `y{motion}` | Yank (copy)                                 |
| `v{motion}` | Select (then `d`, `c`, `y`)                 |
| `p`         | Paste after cursor                          |
| `P`         | Paste before cursor                         |
| `u`         | Undo                                        |
| `Ctrl-r`    | Redo                                        |
| `x`         | Delete character under cursor               |
| `s`         | Substitute character (delete + Insert mode) |
| `o`         | Open new line below, enter Insert mode      |
| `O`         | Open new line above, enter Insert mode      |
| `~`         | Flip case of character                      |
| `J`         | Join current line with the next             |

**Verb + noun combinations:**

```
dw   → delete word
d$   → delete to end of line
d0   → delete to beginning of line
dd   → delete entire line
cw   → change word (delete word + enter Insert mode)
yy   → yank (copy) entire line
3dd  → delete 3 lines
5w   → move forward 5 words
```

**Modifiers — `i` (inner) and `a` (around):**

These are perhaps the most powerful Vim feature for code editing:

```
ci"  → change inside double quotes (cursor anywhere inside them)
ci(  → change inside parentheses
ci[  → change inside square brackets
ci{  → change inside curly braces
da"  → delete a quoted string including the quotes
dib  → delete inside a block (parentheses)
yit  → yank inside an HTML tag
```

***

#### Language Servers and the LSP

Before the **Language Server Protocol (LSP)**, every editor had to implement language intelligence for every language from scratch. VS Code needed its own Python integration, Vim needed its own, Emacs needed its own — N editors × M languages = N×M separate implementations.

LSP, introduced by Microsoft in 2016, changed this to N + M: each language writes **one language server**, and each editor writes **one LSP client**. They speak a common protocol.

```
Editor (VS Code, Vim, Emacs) ←── LSP protocol ──→ Language Server (Pylance, gopls, rust-analyzer)
```

What a language server provides:

| Feature                  | What it does                                   |
| ------------------------ | ---------------------------------------------- |
| **Code completion**      | `object.` → shows fields and methods with docs |
| **Inline documentation** | Hover over a function → see its docstring      |
| **Jump to definition**   | Go from a call site to where it's defined      |
| **Find all references**  | Find every place a symbol is used              |
| **Rename symbol**        | Rename a variable/function everywhere at once  |
| **Import management**    | Auto-add missing imports, remove unused ones   |
| **Inline diagnostics**   | Red squiggles under errors as you type         |
| **Code formatting**      | Auto-indent and format on save                 |

To use this in VS Code: install the language extension (e.g., "Python"), which pulls in the language server automatically. Then point it to your Python environment so it can see your installed packages.

***

#### AI-Powered Development

AI tools for coding exist on a spectrum of **autonomy and context**:

| Form factor       | Interaction model                   | Scope                 |
| ----------------- | ----------------------------------- | --------------------- |
| **Autocomplete**  | Passive, suggests at cursor         | Single function/block |
| **Inline chat**   | You select code, describe a change  | Single selection      |
| **Coding agents** | You describe a task, agent executes | Entire codebase       |

**Autocomplete**

AI autocomplete is driven by **context** — the file you're editing, surrounding code, imports, and especially **comments and naming**. A well-named function with a descriptive comment generates dramatically better completions than a vague one:

```python
# Vague — model guesses incorrectly
def extract(content: str) -> list[str]:
    # model might autocomplete a generic filter

# Clear — model completes correctly
def extract_markdown_links(content: str) -> list[str]:
    # extract all Markdown links from the content
    # model correctly generates a regex-based implementation
```

**Inline Chat**

Inline chat lets you **describe an edit** to existing code rather than writing from scratch. Select a block, invoke the chat, describe what you want:

* "use built-in libraries instead of requests"
* "add error handling for network failures"
* "convert this loop to a list comprehension"
* "write a docstring for this function"

The model proposes a diff — you accept, reject, or iterate.

**Coding Agents**

Agents (like Claude Code) are covered in the Agentic Coding lecture. The key shift: instead of assisting with individual edits, they accept high-level goals and autonomously plan and execute multi-step changes across files, run tests, and iterate.

***

#### IDE Extensions

Extensions are what turn an editor into a full development environment. Key categories:

**Dev Containers** — run your entire dev environment inside a Docker container, defined by a `.devcontainer/devcontainer.json` file. Benefits:

* Same environment on every developer's machine
* No "works on my machine" issues
* Instantly reproducible from a fresh clone

**Remote SSH** — edit files on a remote machine as if they were local. VS Code handles file sync and port forwarding transparently. Key use case: developing on a GPU server in the cloud without leaving your local IDE.

**Live Share** — real-time collaborative editing, like Google Docs but in VS Code. Both developers can navigate and edit the same files simultaneously, including shared terminal sessions.

***

### Mental Model

#### Vim: The Grammar Analogy

Think of Vim's Normal mode as a **small programming language** with a grammar:

```
[count] verb [modifier] noun

Examples:
  d    w     → delete word
  3    d     w     → delete 3 words
  c    i     "     → change inside quotes
  y    $           → yank to end of line
  5    j           → move down 5 lines
```

Once you internalize this grammar, you don't learn individual commands — you learn **the language**, and then compose sentences. A new combination like `d2t,` (delete to the second comma) is immediately readable and typeable even if you've never used it before.

This is why Vim users describe it as "thinking in Vim" — after enough practice, the mechanics become as unconscious as touch-typing.

***

#### Modal Editing: The Mode as Context

Think of Vim's modes like a **context switch** in your brain:

```
Normal mode = Navigation brain
  "Where am I? What do I want to change?"
  Move fast. Survey the file. Plan the edit.

Insert mode = Typing brain
  "I know exactly what text goes here."
  Type it. Get out with <ESC>.

Visual mode = Selection brain
  "I need to operate on this exact region."
  Select precisely. Apply a verb.
```

The mistake beginners make: staying in Insert mode to navigate (using arrow keys). This throws away the entire benefit of the modal model. The rule of thumb: **if you're not actively typing new text, press `<ESC>` and use Normal mode**.

***

#### Language Servers: Semantic vs. Syntactic Understanding

Traditional syntax highlighting (even regex-based) gives you **syntactic** understanding — it knows `def` is a keyword and `str` is a type name. Language servers give **semantic** understanding — they know that *this specific* `str` is a parameter, that `object.field` refers to *this* field defined on line 47 of *that* file, and that renaming it safely requires changing 12 other places.

```
Syntax highlighting:   "This token looks like a function name"
Language server:       "This token IS function parse_config, defined in
                        config.py:34, called in 7 other files, 
                        accepts Dict[str, str], returns Config"
```

The language server maintains a live, up-to-date semantic model of your whole project as you type.

***

#### AI Autocomplete: Guided by Context

Think of AI autocomplete as a very capable **collaborator who can only see your current file**. Your job is to give it enough context to complete correctly:

```
Poor context → generic completion:
  def f(x):        →  return x + 1  (reasonable guess, probably wrong)

Rich context → precise completion:
  def parse_iso_datetime(timestamp: str) -> datetime:
      # Parse an ISO 8601 timestamp string into a datetime object
      # Handle both 'Z' and '+00:00' UTC suffixes
      →  (correct implementation using datetime.fromisoformat)
```

Comments act as **prompts**. Descriptive names act as prompts. Type annotations act as prompts. The more context you give, the more precisely it completes.

***

### Commands and Syntax

#### Vim: Entering and Exiting

```vim
vim filename       " open a file
:w                 " save (write)
:q                 " quit
:wq                " save and quit
:q!                " quit without saving (discard changes)
:e filename        " open another file
```

***

#### Vim: Mode Transitions

```
<ESC>              → Return to Normal mode from anywhere
i                  → Insert mode (before cursor)
a                  → Insert mode (after cursor)
A                  → Insert mode (end of line)
I                  → Insert mode (beginning of line)
o                  → Insert mode on new line below
O                  → Insert mode on new line above
R                  → Replace mode
v                  → Visual (character) mode
V                  → Visual Line mode
Ctrl-v             → Visual Block mode
:                  → Command-line mode
```

***

#### Vim: Saving and Searching

```vim
:w                 " save current file
:wq                " save and quit
/pattern           " search forward
?pattern           " search backward
n                  " next match
N                  " previous match
:%s/old/new/g      " replace all occurrences in file
:%s/old/new/gc     " replace with confirmation for each
:noh               " clear search highlights
```

***

#### Vim: Power Combinations Reference

```vim
" Navigation
gg                 " go to top of file
G                  " go to bottom of file
50G                " go to line 50
:50<CR>            " go to line 50 (command mode)
Ctrl-u             " scroll up half screen
Ctrl-d             " scroll down half screen

" Editing
dd                 " delete (cut) current line
yy                 " copy current line
p                  " paste below
P                  " paste above
u                  " undo
Ctrl-r             " redo
.                  " repeat last change (very powerful)

" Text objects
ci"                " change inside double quotes
ci(                " change inside parentheses
ci{                " change inside curly braces
da"                " delete around (including) quotes
dib                " delete inside block/parentheses

" Multiple operations
3dd                " delete 3 lines
5yy                " copy 5 lines
d3w                " delete 3 words
```

***

#### VS Code: Key Commands for LSP Features

```
F12               → Jump to definition
Shift+F12         → Find all references
F2                → Rename symbol
Shift+Alt+F       → Format document
Ctrl+.            → Quick fix / suggested imports
Ctrl+Space        → Trigger autocomplete manually
Ctrl+Shift+P      → Command palette (search all commands)
Ctrl+`            → Open/focus integrated terminal
```

***

#### `vimtutor`

```bash
vimtutor
```

An interactive, self-paced Vim tutorial built into most Vim installations. Covers all fundamentals in \~30 minutes of hands-on practice. Run it from your terminal.

***

### Command Flow Diagrams

#### Vim Mode State Machine

```mermaid
stateDiagram-v2
    [*] --> Normal : vim opens

    Normal --> Insert : i / a / o / A / I / O
    Normal --> Replace : R
    Normal --> Visual : v
    Normal --> VisualLine : V
    Normal --> VisualBlock : Ctrl-v
    Normal --> CommandLine : :

    Insert --> Normal : <ESC>
    Replace --> Normal : <ESC>
    Visual --> Normal : <ESC>
    VisualLine --> Normal : <ESC>
    VisualBlock --> Normal : <ESC>
    CommandLine --> Normal : <Enter> or <ESC>

    Visual --> Insert : c (change selection)
    VisualLine --> Insert : c
    VisualBlock --> Insert : c

    note right of Normal
        Home base.
        All navigation happens here.
        Most time spent here.
    end note

    note right of Insert
        Brief visits only.
        Type the text.
        Return to Normal.
    end note
```

***

#### The Language Server Protocol Architecture

```mermaid
graph TB
    subgraph "Your Editor (LSP Client)"
        E1["VS Code"]
        E2["Vim + nvim-lspconfig"]
        E3["Emacs + eglot"]
    end

    subgraph "Language Servers (LSP Servers)"
        L1["Pylance\n(Python)"]
        L2["gopls\n(Go)"]
        L3["rust-analyzer\n(Rust)"]
        L4["tsserver\n(TypeScript)"]
    end

    E1 <-->|LSP protocol\nover stdio/TCP| L1
    E1 <-->|LSP protocol| L2
    E2 <-->|LSP protocol| L3
    E3 <-->|LSP protocol| L4

    L1 --> P1["Your Python\npackages & types"]
    L2 --> P2["Go modules\n& stdlib"]
    L3 --> P3["Cargo.toml\ndependencies"]

    style E1 fill:#1a3a5c,color:#fff
    style E2 fill:#1a3a5c,color:#fff
    style E3 fill:#1a3a5c,color:#fff
    style L1 fill:#2d4a22,color:#fff
    style L2 fill:#2d4a22,color:#fff
    style L3 fill:#2d4a22,color:#fff
    style L4 fill:#2d4a22,color:#fff
```

***

#### AI Tool Spectrum: Autonomy vs. Scope

```mermaid
graph LR
    A["Autocomplete\n─────────────\nPassive\nSingle location\nCursor-driven"] -->|more autonomy| B["Inline Chat\n─────────────\nOn demand\nSelected region\nPrompt-driven"]
    B -->|more autonomy| C["Coding Agent\n─────────────\nProactive\nEntire codebase\nGoal-driven"]

    style A fill:#1a3a5c,color:#fff
    style B fill:#2d4a22,color:#fff
    style C fill:#4a2d00,color:#fff
```

***

#### Vim Grammar: Verb + Noun Composition

```mermaid
graph TD
    CMD["Vim Command"]
    COUNT["Count (optional)\n2, 3, 5..."]
    VERB["Verb\nd=delete\nc=change\ny=yank\nv=select"]
    MOD["Modifier (optional)\ni=inner\na=around"]
    NOUN["Noun / Motion\nw=word\n$=end of line\n(=parenthesis\n\"=quotes"]

    CMD --> COUNT
    CMD --> VERB
    CMD --> MOD
    CMD --> NOUN

    COUNT -->|"3dw = delete 3 words"| RESULT["Editing\nAction"]
    VERB --> RESULT
    MOD -->|"ci( = change inside ()"| RESULT
    NOUN --> RESULT

    style VERB fill:#4a1a00,color:#fff
    style NOUN fill:#1a3a5c,color:#fff
    style MOD fill:#2d4a22,color:#fff
    style COUNT fill:#3a2d4a,color:#fff
```

***

#### Dev Environment: Terminal vs. IDE Comparison

```mermaid
graph TB
    subgraph "Terminal-based Stack"
        T1["tmux\n(window management)"]
        T2["Vim / Neovim\n(text editing)"]
        T3["nvim-lspconfig\n(language intelligence)"]
        T4["ruff / mypy\n(linting & types)"]
        T5["zsh + fzf\n(shell & search)"]
        T1 --- T2
        T2 --- T3
        T3 --- T4
        T4 --- T5
    end

    subgraph "IDE-based Stack (VS Code)"
        I1["VS Code\n(integrated environment)"]
        I2["Language Extension\n(Python / Go / Rust...)"]
        I3["Language Server\n(Pylance / gopls...)"]
        I4["GitHub Copilot\n(AI assistance)"]
        I5["Remote SSH / DevContainers\n(remote development)"]
        I1 --- I2
        I2 --- I3
        I3 --- I4
        I4 --- I5
    end

    BOTH["Shared benefits:\nSame LSP protocol\nSame AI models\nSame underlying tools"]

    T1 -.->|converging on| BOTH
    I1 -.->|converging on| BOTH

    style BOTH fill:#2d2d2d,color:#fff
```

***

### Real-World Workflows

#### Fixing a Bug in Vim: The FizzBuzz Walkthrough

Given this broken Python file open in Vim:

```python
def fizz_buzz(limit):
    for i in range(limit):        # Bug 1: should be range(1, limit + 1)
        if i % 3 == 0:
            print("fizz", end="")
        if i % 5 == 0:
            print("fizz", end="") # Bug 2: should print "buzz"
        if i % 3 and i % 5:
            print(i, end="")
        print()

def main():
    fizz_buzz(20)
                                   # Bug 3: main() is never called
```

Vim command sequence to fix all three bugs (starting in Normal mode):

```vim
" Fix Bug 3: add main guard at end of file
G                    → jump to end of file
o                    → open new line below, enter Insert mode
if __name__ == "__main__": main()
<ESC>                → back to Normal mode

" Fix Bug 1: add '1,' to range(...)
/range<CR>           → search for "range"
ww                   → jump forward 2 words (land inside the parens)
i                    → Insert mode
1,                   → type the missing start
<ESC>                → Normal mode
e                    → jump to end of next word (the closing paren)
a                    → append after cursor
+ 1                  → add the offset
<ESC>                → Normal mode

" Fix Bug 2: change "fizz" to "buzz" on line 6
:6<CR>               → jump to line 6
ci"                  → change inside double quotes
buzz                 → type the correct string
<ESC>                → Normal mode

" Save
:w<CR>               → write the file
```

Every edit was expressed as a composed command. No mouse. No arrow keys.

***

#### Setting Up Python Intelligence in VS Code

```
1. Open VS Code
2. Ctrl+Shift+X → Extensions panel
3. Search "Python" → Install Microsoft's Python extension
   (this installs Pylance language server automatically)

4. Open a .py file
5. Bottom bar → click the Python version selector
6. Choose your project's virtual environment

Now available:
  - Ctrl+Space        → semantic autocomplete
  - Hover over symbol → inline docs
  - F12               → jump to definition (even into library source)
  - Shift+F12         → find all usages in project
  - F2                → safe rename across all files
```

***

#### Using AI Autocomplete Effectively

```python
# Pattern 1: Descriptive function names guide completions
def calculate_compound_interest(principal: float, rate: float, years: int) -> float:
    # AI completes correctly because the name is self-describing

# Pattern 2: Comments as prompts
def process_user_data(raw_data: dict) -> User:
    # validate required fields are present
    # normalize email to lowercase
    # parse date fields as datetime objects
    # return a User dataclass instance
    # AI generates each step correctly when guided by comments

# Pattern 3: Type annotations as contracts
def merge_configs(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
    # The type signature tells the AI exactly what to produce
```

***

#### Remote Development with VS Code + SSH

```
1. Install "Remote - SSH" extension in VS Code

2. Ctrl+Shift+P → "Remote-SSH: Connect to Host"
3. Enter: alice@gpu-server.company.com

VS Code now:
  - Runs extensions ON the remote machine
  - Indexes the remote codebase for language intelligence
  - Runs your terminal in the remote shell
  - Forwards ports transparently (localhost:8080 → remote:8080)

The experience is identical to local development,
but all compute happens on the remote server.
```

***

#### Dev Container Workflow

```json
// .devcontainer/devcontainer.json in your project
{
  "name": "Python Dev",
  "image": "mcr.microsoft.com/devcontainers/python:3.12",
  "features": {
    "ghcr.io/devcontainers/features/git:1": {}
  },
  "postCreateCommand": "pip install -r requirements.txt",
  "customizations": {
    "vscode": {
      "extensions": ["ms-python.python", "ms-python.vscode-pylance"]
    }
  }
}
```

Any developer clones the repo and opens it in VS Code → prompted to "Reopen in Container" → identical environment, every time. No setup instructions. No dependency conflicts.

***

### Productivity Tricks

#### Remap Caps Lock to Escape

Caps Lock is in prime real estate (left of `A`) but almost never useful. `<ESC>` is used constantly in Vim but sits far away in the top-left corner. Swap them:

* **macOS:** System Settings → Keyboard → Keyboard Shortcuts → Modifier Keys → Caps Lock → Escape
* **Linux:** `setxkbmap -option caps:escape` (add to `~/.bashrc`)
* **Windows:** Use PowerToys → Keyboard Manager

After this, modal editing becomes dramatically less awkward.

***

#### The `.` Repeat Command

The single most underused Vim command is `.` in Normal mode — it **repeats the last change**. Combine this with search:

```vim
/old_function_name<CR>  → search for first occurrence
cgn                     → change the next match (enters Insert mode)
new_function_name       → type replacement
<ESC>                   → back to Normal
.                       → repeat the change on next match
n.                      → skip one, change next
```

This is often faster than `:%s/.../...g` for selective replacements.

***

#### `vimtutor` — 30 Minutes to Baseline Fluency

```bash
vimtutor
```

Run this once, follow it completely. It covers exactly the commands needed for day-to-day editing. After `vimtutor`, enable Vim mode in your IDE and **commit to it for a month** — that's the only way to build muscle memory.

***

#### VS Code Command Palette as Universal Search

`Ctrl+Shift+P` opens a fuzzy-searchable list of every VS Code command. You almost never need to memorize menu locations:

```
> format document          → run formatter
> rename symbol            → safe rename
> open settings json       → edit settings.json directly
> install extensions       → browse marketplace
> python: select interpreter → switch virtualenv
```

***

#### fzf Integration with Vim

If you use Neovim or have the `fzf.vim` plugin, you get fuzzy file finding, buffer switching, and git log browsing inside Vim:

```vim
:Files      " fuzzy-find files in project
:Buffers    " switch between open buffers
:GFiles     " git-tracked files only
:Rg query   " ripgrep across project, fuzzy filter results
```

***

### Common Mistakes

#### ❌ Living in Insert Mode

**Wrong workflow:**

```
Open file → press i → navigate with arrow keys → type → arrow keys → type → :wq
```

**Correct workflow:**

```
Open file → Normal mode → navigate with hjkl/w/b/f → press i only to type → <ESC> → Normal mode
```

**Why:** Insert mode is for entering text, not for navigating. Every navigation keystroke in Insert mode (arrow keys) is slower than the equivalent Normal-mode motion. The payoff of Vim only arrives when Normal mode becomes your default state.

***

#### ❌ Ignoring Type Annotations for LSP

**Wrong:**

```python
def process(data):
    # Language server has no idea what 'data' is
    # No autocomplete on data.fields
    # No type error detection
```

**Correct:**

```python
def process(data: UserRecord) -> ProcessedResult:
    # Language server knows the full shape of data
    # Autocomplete shows data.name, data.email, etc.
    # Type errors flagged inline before running
```

***

#### ❌ Using Arrow Keys in Vim

Arrow keys work in Insert mode but destroy your muscle memory and slow you down. The fix is radical but effective:

```vim
" Add to ~/.vimrc to disable arrow keys entirely
noremap <Up>    <Nop>
noremap <Down>  <Nop>
noremap <Left>  <Nop>
noremap <Right> <Nop>
```

After a week of discomfort, `hjkl` becomes automatic.

***

#### ❌ Accepting AI Completions Without Reading Them

AI autocomplete is fast but not infallible. Common failure modes:

* Uses a deprecated API
* Puts `import` statements inside functions instead of at module level
* Generates plausible-looking but logically wrong code
* Introduces subtle off-by-one errors

**Rule:** Read every AI completion before accepting it. For anything non-trivial, run the tests.

***

#### ❌ Installing a Giant Plugin Framework Instead of Individual Plugins

Oh-My-Zsh and Prezto are convenient but add hundreds of milliseconds to shell startup time and include dozens of plugins you'll never use. Same with Vim plugin collections.

**Better approach:** Install exactly what you need, one plugin at a time. Each plugin you install, you understand. Your shell stays fast.

```bash
# Measure your shell startup time
time zsh -i -c exit
# If > 200ms, something is slowing you down
```

***

#### ❌ Not Pointing VS Code at Your Virtual Environment

```
Symptom: F12 (jump to definition) doesn't work for installed packages.
         Red squiggles under valid imports.
         Autocomplete doesn't know library types.

Fix: Ctrl+Shift+P → "Python: Select Interpreter"
     Choose the .venv or conda environment for your project
```

***

### Exercises

#### Beginner Exercises

1. **Install and open Vim:**

   ```bash
   vim /tmp/practice.txt
   ```

   Enter Insert mode (`i`), type a few lines, exit Insert mode (`<ESC>`), save and quit (`:wq`). Repeat until the mode transitions feel natural.
2. **Run `vimtutor`:**

   ```bash
   vimtutor
   ```

   Complete all seven lessons. Don't rush — the goal is fluency, not speed. Budget 30–45 minutes.
3. **Enable Vim mode in your IDE:** In VS Code, install the **VSCodeVim** extension. In your shell (if using Zsh), add `bindkey -v` to `~/.zshrc`. Use Vim mode for all editing for one week and note where you get stuck.
4. **Explore LSP features:** Open a Python (or any other language) file in VS Code with the language extension installed. Try:
   * Hovering over a function call to see its signature
   * Pressing `F12` on a library function to jump to its definition
   * Using `Ctrl+Space` to trigger autocomplete after `os.`
5. **AI autocomplete experiment:** Write two versions of the same function — one with a vague name and no comments, one with a descriptive name and a comment explaining its purpose. Compare the AI completions. Which is better?

***

#### Intermediate Exercises

6. **FizzBuzz fix in Vim:** Copy the broken FizzBuzz code from the Walkthrough section into a file. Fix all three bugs using only Normal-mode Vim commands — no mouse, no arrow keys. Time yourself on the first attempt, then repeat until it feels natural.
7. **Text objects practice:** Open any code file in Vim. Practice these operations:
   * `ci"` — change the content of a string literal
   * `ci(` — change the arguments inside a function call
   * `da{` — delete an entire code block including braces
   * `yib` — copy the contents inside parentheses For each one, find a real place in the code to apply it.
8. **Language server rename:** In a project with LSP set up, use `F2` (rename symbol) to rename a variable or function that's used in multiple places. Verify all references were updated correctly. Compare this to a manual find-and-replace.
9. **Inline chat refactor:** Take a function that uses a third-party library. Use your IDE's inline chat to ask it to "rewrite using only standard library". Review and accept the proposal. Does it work?
10. **Measure what you use:** Run:

    ```bash
    history | awk '{$1="";print substr($0,2)}' | sort | uniq -c | sort -rn | head -20
    ```

    Of those commands, which ones would benefit from IDE/LSP support vs. terminal tools? This tells you where to invest in environment setup.

***

#### Advanced Challenge

11. **VimGolf:** Go to [vimgolf.com](https://www.vimgolf.com/) and complete one challenge. The goal is to perform a text transformation in the fewest possible keystrokes. Study the posted solutions afterward — they reveal Vim idioms you might not discover on your own.
12. **Set up a full language server for a real project:**
    * Clone an open-source project (e.g., [cobra](https://github.com/spf13/cobra) for Go, or a Python project)
    * Configure VS Code with the appropriate language extension and point it at the project
    * Verify that:
      * Jump-to-definition works for a library dependency (not just local files)
      * Find-all-references works across multiple files
      * Rename symbol safely refactors across the codebase
      * Inline errors appear without running the code
13. **Dev container from scratch:** For a project you're working on (or a sample project), create a `.devcontainer/devcontainer.json` that:
    * Uses a language-appropriate base image
    * Installs your project's dependencies in `postCreateCommand`
    * Pre-installs your preferred VS Code extensions
    * Works on a colleague's machine with `git clone` → "Reopen in Container"
14. **Vim config bootstrapping:** Create a minimal `~/.vimrc` that includes:

    ```vim
    syntax on
    set number
    set relativenumber
    set tabstop=4
    set shiftwidth=4
    set expandtab
    set incsearch
    set hlsearch
    inoremap jk <ESC>    " escape with jk
    ```

    Add it to your dotfiles repo. Verify it loads correctly with `vim --version` and `vim +':set number?' +q`.

***

### Summary

| Topic                        | Core Idea                                                                         |
| ---------------------------- | --------------------------------------------------------------------------------- |
| **Dev environment**          | A layered stack: editor + language intelligence + quality tools + AI + extensions |
| **Vim philosophy**           | Interface is a composable programming language; keystrokes are verbs and nouns    |
| **Modal editing**            | Normal mode = default; Insert mode = brief visits for typing only                 |
| **Vim movement**             | `hjkl`, `w/b/e`, `0/$/gg/G`, `f{c}`, `/{pattern}` — navigate without mouse        |
| **Vim editing**              | `d`, `c`, `y`, `p` + motions + `i`/`a` modifiers = surgical edits                 |
| **LSP**                      | One protocol, N editors × M languages → N+M implementations                       |
| **Language server features** | Completion, hover docs, jump-to-def, find refs, rename, inline errors             |
| **AI autocomplete**          | Context-driven; guided by names, types, and comments                              |
| **AI inline chat**           | Describe edits to selected code; model proposes a diff                            |
| **Coding agents**            | Goal-level autonomy over entire codebase                                          |
| **Dev containers**           | Reproducible environments from `.devcontainer.json`                               |
| **Remote SSH**               | Full IDE experience on a remote machine                                           |

#### Most Important Commands from This Lecture

```vim
" Vim essentials
i / <ESC>      → enter / exit Insert mode
hjkl           → left / down / up / right
w / b / e      → word forward / back / end
0 / $          → line start / end
gg / G         → file start / end
/{pattern}     → search
d{motion}      → delete
c{motion}      → change (delete + insert)
y{motion}      → yank (copy)
p / P          → paste after / before
ci" / ci(      → change inside quotes / parentheses
u / Ctrl-r     → undo / redo
.              → repeat last change
:w / :q / :wq  → save / quit / save+quit
```

```
" VS Code essentials
F12            → jump to definition
Shift+F12      → find all references
F2             → rename symbol
Ctrl+Shift+P   → command palette
Ctrl+.         → quick fix / auto-import
```

#### What's Next

In **Lecture 4 – Debugging and Profiling**, you'll learn systematic approaches to finding and fixing bugs — from reading tracebacks and using interactive debuggers, to profiling CPU and memory usage to find performance bottlenecks in your code.

***

*Source:* [*MIT Missing Semester – Development Environment and Tools*](https://missing.csail.mit.edu/2026/development-environment/) *Licensed under* [*CC BY-NC-SA 4.0*](https://creativecommons.org/licenses/by-nc-sa/4.0)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shankar-lab.gitbook.io/mylearning/the-missing-semester-of-your-cs-education/lecture-3-development-environment-and-tools.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
