Project 2: The JSON Surgeon
Safely edit nested JSON values and arrays using text objects and operators.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Intermediate |
| Time Estimate | 10-15 hours |
| Main Programming Language | JSON |
| Alternative Programming Languages | YAML, TOML |
| Coolness Level | Level 2: Precision Tooling |
| Business Potential | Level 3: Data Cleaner |
| Prerequisites | Text objects basics, Operator + motion grammar |
| Key Topics | Text Objects and Inner/Around, Operators and Change Types |
1. Learning Objectives
By completing this project, you will:
- Execute the core workflow for The JSON Surgeon without Visual mode.
- Apply motion-based edits to achieve a measurable output.
- Explain the reasoning behind each key command you used.
- Validate results against a deterministic outcome.
2. All Theory Needed (Per-Concept Breakdown)
Text Objects and Inner/Around
Fundamentals
Text objects are semantic selections that ignore cursor position. The i (inner) and a (around) prefixes let you select the object itself or the object plus surrounding whitespace or delimiters. This is different from motions because text objects are stable inside a structure. If your cursor is anywhere inside a quoted string, i" selects the inside and a" selects the quotes too. Text objects are the most reliable way to edit structured data because they map to meaning rather than location.
Text objects are stable regardless of cursor position, which is why they feel so reliable. If you are inside a block, the object finds the boundaries for you. This makes edits safer in nested structures.
Deep Dive
Text objects turn Vim into a structural editor. The key idea is that they describe what you are inside: a word, a quoted string, a paragraph, a bracket pair, a tag. This removes the need to count or to move to a boundary before editing. When you use an operator with a text object, Vim finds the surrounding object boundaries and applies the operator to that region. This is why ci" works even if the cursor is in the middle of the string. The distinction between inner and around is essential for correctness. i excludes surrounding whitespace or delimiters, while a includes them. For example, daw removes the word and one trailing space, which is perfect for deleting list items without leaving double spaces. diw removes only the word, leaving spacing intact. This difference becomes critical when editing punctuation-separated data like CSV or JSON.
Text objects are not limited to words or quotes. There are objects for parentheses, brackets, braces, tags, and even sentences or paragraphs. You can combine them with any operator. This composability is the engine of fast structural editing. For instance, in HTML you can use cit to change the inner content of a tag, while dat removes the entire tag. In code, ci( changes function arguments, and da{ removes a whole block. The same idea applies to markdown: cip changes an entire paragraph without touching surrounding blank lines.
Text objects are especially powerful because they align with your intent. You do not say “go to the next quote and delete”; you say “change inside this quote.” This reduces cognitive load, because you think in semantics rather than coordinates. The operator + text object grammar also makes changes repeatable, which is crucial for dot command and macros. If you perform a change using a text object, you can often repeat it on the next occurrence without adjustment. This is not always true with raw motions because the motion distance may change.
There are edge cases. For example, if a string contains escaped quotes, the text object may behave unexpectedly depending on filetype settings. If you are inside nested parentheses, Vim chooses the nearest surrounding pair. Learning to predict which pair is “inner” is important. You should also know that some text objects depend on filetype plugins. For example, it and at for HTML tags are provided by matchit or filetype support. In a minimal Vim, some objects may not exist. This is why you should test your environment and understand what is built-in versus filetype-defined.
Text objects also change how you design macros. A macro that uses ci" or di] will adapt to different line lengths and formatting, because it depends on structure. This is why they are more robust than motions like 3w or f,. For long-term mastery, you should default to text objects whenever you are working with structured data or delimited text. They are the highest-leverage Vim concept for editing code and configuration files.
Nested objects introduce edge cases: if you are inside nested parentheses, ci( targets the nearest pair; to reach the outer pair, you must move outward first. Filetype plugins can add objects like it for tags or ic for comments. If an object does not work, check whether filetype detection is enabled and whether the object is defined.
How this fit on projects Projects 2, 3, 6, and 10 use text objects as primary targets.
Definitions & key terms
- Inner object: excludes surrounding whitespace or delimiters (
iw,i") - Around object: includes surrounding whitespace or delimiters (
aw,a") - Delimiter: quote, bracket, brace, or tag boundary
Mental model diagram
[a object] = [whitespace + object + whitespace]
[i object] = [object only]
How it works
- Choose an operator.
- Choose
iora. - Choose the object (word, quote, bracket, paragraph, tag).
- Vim finds boundaries and applies the operator.
Minimal concrete example
ci"
daw
yip
ci(
Common misconceptions
- “Text objects only work in Visual mode.” (They also work after operators.)
- “
iwis the same asw.” (Objects are semantic, motions are positional.) - “You must be on the first character.” (Any position inside works.)
Check-your-understanding questions
- What does
ci(do? - When is
dawbetter thandw? - What is the difference between
a"andi"?
Check-your-understanding answers
- Changes the text inside parentheses.
- When you want the whole word removed including trailing space.
a"includes quotes;i"excludes them.
Real-world applications
- Editing JSON values safely
- Refactoring function arguments
- Wrapping or removing HTML tags
Where you’ll apply it Projects 2, 3, 6, 10.
References
- Vim
:help text-objects - Vim
:help object-select - “Practical Vim” - Ch. 4
Key insights Text objects let you edit structure without counting.
Summary Text objects are the fastest way to edit structured text reliably.
Homework/Exercises to practice the concept
- In JSON, use
ci"to edit values without touching quotes. - In code, use
da(to remove argument lists.
Solutions to the homework/exercises
ci"changes the value, keeping quotes intact.da(deletes arguments and parentheses together.
Operators and Change Types
Fundamentals
Operators are the verbs of Vim: delete, change, yank, indent, format, case-convert, filter. They determine what happens to a range of text defined by a motion or text object. Understanding operators reduces command memorization because you can express edits in a few primitives. For example, if you know d is delete and ap is a paragraph, then dap is obvious. The operator set is small but powerful, and it becomes more powerful when paired with motions and text objects.
Operators also determine the shape of the change: characterwise, linewise, or blockwise. The motion you choose controls that shape, which affects how text is stored in registers and how it pastes later.
Deep Dive
Operators fall into categories. Destructive operators include delete (d) and change (c), which remove text (and in the case of c, also enter Insert mode). Copying operators include yank (y) and sometimes Y for linewise yank. Formatting operators include indent (> and <), reformat (gq), and filter (!). Case operations (gU, gu, g~) are transformations. Each operator interacts with motions to define a range. For example, gqap means “format a paragraph,” while >i{ means “indent inside braces.” Operators also define what gets placed in registers: delete and change write to registers, yank writes to register 0 and unnamed register, and some operators use specific registers. This is important because operators affect your clipboard history.
Change (c) is one of the most important operators because it includes both deletion and insertion, creating a single change for repeatability. This makes it ideal for dot command repetition. For example, cw changes the rest of a word and leaves you in Insert mode; this is faster and more repeatable than dw followed by i. Understanding this difference changes how you do refactors. Similarly, C is shorthand for c$, and D is shorthand for d$. These linewise shorthands are part of the operator vocabulary.
Indenting and formatting operators are critical in code and prose. Indenting with > and < is linewise by default when used with a count or a linewise motion. Formatting with gq respects textwidth and can be used to wrap comments or paragraphs. Filtering with ! sends a range through an external command. This is extremely powerful but can be dangerous if the command is destructive or unavailable. When using !, you should verify the command on a small range first.
Operators also have edge cases: some are linewise by default, some are characterwise, and some become linewise when doubled. The exact behavior depends on the motion used. If you use a linewise motion (like j with a count or }), you get a linewise operation. If you use a characterwise motion, you get a characterwise operation. This matters for registers and for how the change can be repeated. A good habit is to think about the shape of the operation: characterwise, linewise, or blockwise. Vim supports all three, and you should pick the one that aligns with your intent.
Operators also interact with the . repeat command. A clean operator-based change is usually easy to repeat; a complicated multi-step edit may not be. This is why many Vim users prioritize operator + motion patterns over Visual selection. The operator grammar leads to edits that are shorter and more repeatable. Once you can mentally separate “what to do” from “where to do it,” operators become a compact toolbox rather than a long list of shortcuts.
Beyond the core operators, g~ toggles case, = reindents using filetype rules, and ! filters a range through an external command. These operators are powerful but should be used with clear scope and a preview when possible. Because operator-based changes are a single change, they integrate cleanly with the dot command and undo history. This makes them safer than multi-step edits.
How this fit on projects Projects 2-6 rely on operators for deletion, change, formatting, and indentation.
Definitions & key terms
- Delete (
d): remove text - Change (
c): delete and enter Insert mode - Yank (
y): copy into a register - Indent (
>/<): shift lines - Format (
gq): reflow text - Filter (
!): pipe range through external command
Mental model diagram
Operator chooses action; motion chooses target.
How it works
- Type an operator.
- Provide a motion or text object.
- Vim applies the operator to the computed range.
- The change is stored in registers and can be repeated.
Minimal concrete example
gUiw
>ap
gqip
Common misconceptions
- “Change and delete are unrelated.” (
cisd+ Insert.) - “Indent only works in Visual mode.” (Operators work with motions.)
- “Formatting requires plugins.” (
gqis built in.)
Check-your-understanding questions
- What is the difference between
dandc? - What does
gqapdo? - How do you lowercase inside quotes?
Check-your-understanding answers
ddeletes;cdeletes and enters Insert.- Formats (wraps) a paragraph.
gui".
Real-world applications
- Refactoring identifiers
- Indenting code blocks
- Formatting comments or prose
Where you’ll apply it Projects 2-6.
References
- Vim
:help operator - Vim
:help change.txt - “Practical Vim” - Ch. 1-5
Key insights Operators are verbs; everything else is grammar.
Summary Learn operators and you can express any edit with a motion.
Homework/Exercises to practice the concept
- Uppercase three words with a single command.
- Re-indent a function with one operator.
Solutions to the homework/exercises
gU3wuppercases three words.=apor>apdepending on indent settings.
3. Project Specification
3.1 What You Will Build
A set of repeatable edits that update a nested JSON payload without breaking structure.
Included:
- Nested objects
- Arrays with multiple elements
- Quoted values
Excluded:
- Schema validation tooling
- External formatters
3.2 Functional Requirements
- Core workflow: Change specific values with inner/around text objects
- Repeatability: Remove array elements without leaving dangling commas
- Validation: Apply the same change across multiple keys with search + dot
3.3 Non-Functional Requirements
- Performance: Edits should be repeatable with dot or a short sequence.
- Reliability: JSON remains valid after each edit.
- Usability: Changes avoid Visual mode for repeatability.
3.4 Example Usage / Output
Use `ci"`, `da{`, and `di]` to update fields and remove array items safely.
3.5 Data Formats / Schemas / Protocols
- JSON object: { “key”: “value” }
- Arrays: [“item1”, “item2”]
3.6 Edge Cases
- Strings with escaped quotes
- Nested arrays
- Trailing commas in non-JSON files
3.7 Real World Outcome
This is the deterministic output you can compare against directly.
3.7.1 How to Run (Copy/Paste)
- vim payload.json
3.7.2 Golden Path Demo (Deterministic)
Update role to “admin” and remove a tag without breaking quotes or brackets.
3.7.3 If CLI: provide an exact terminal transcript
$ vim payload.json
# Use ci"admin<Esc> then di] on the target array element
# Verify structure visually
4. Solution Architecture
4.1 High-Level Design
Input file -> Vim workflow plan -> Verification checklist
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Input File | Provides deterministic data | Keep it stable and versioned |
| Vim Workflow Plan | Documents motions and operators | Prefer repeatable sequences |
| Verification Checklist | Confirms correctness | Use before/after snapshots |
4.4 Data Structures (No Full Code)
- Entry: a structured line or block with fields relevant to the task
- Target: the specific token or structure you will move to or edit
- Checklist: steps to verify the output
4.4 Algorithm Overview
Key Algorithm: Motion-First Editing Loop
- Identify the target structure (word, field, block, or line).
- Choose a motion or text object that selects it safely.
- Apply the operator or edit and verify the result.
Complexity Analysis:
- Time: O(n) over lines edited
- Space: O(1) additional space
5. Implementation Guide
5.1 Development Environment Setup
vim --version
vimtutor
5.2 Project Structure
project-root/
|-- input/
| `-- sample.txt
|-- notes/
| `-- keystrokes.md
`-- outputs/
`-- expected.txt
5.3 The Core Question You’re Answering
“Safely edit nested JSON values and arrays using text objects and operators.”
5.4 Concepts You Must Understand First
Stop and research these before editing:
- Text objects basics
- Operator + motion grammar
5.5 Questions to Guide Your Design
- Which motion or text object targets the structure directly?
- Can the change be repeated with dot or a macro?
- How will you verify correctness after the change?
5.6 Thinking Exercise
Before editing, sketch the steps needed to complete the task on paper.
5.7 The Interview Questions They’ll Ask
- “Which motion did you choose and why?”
- “How did you ensure the edit was repeatable?”
- “What is the risk of using Visual mode here?”
- “How did you validate the output?”
5.8 Hints in Layers
Hint 1: Start with a stable cursor position
Use 0, ^, or a search to align before editing.
Hint 2: Choose the smallest safe unit If a word is enough, use a word object; if not, use a larger object.
Hint 3: Make it repeatable
Design the first change so . works on the next target.
Hint 4: Validate Check before/after snapshots after each batch of edits.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Core workflow | “Practical Vim” | Ch. 1-4 |
| Motions | “Practical Vim” | Ch. 8 |
| Editing language | “Learning the vi and Vim Editors” | Ch. 3 |
5.10 Implementation Phases
Phase 1: Foundation (10-15 hours)
Goals:
- Load the input file and identify targets
- Verify core motions and search behavior
Tasks:
- Create a short checklist of target patterns
- Practice on 3-5 lines
Checkpoint: You can complete the smallest edit without mistakes.
Phase 2: Core Functionality (10-15 hours)
Goals:
- Execute the main workflow end-to-end
- Keep edits repeatable
Tasks:
- Apply the main edit sequence to the full file
- Record keystrokes or a macro if needed
Checkpoint: Output matches the golden path demo.
Phase 3: Polish & Edge Cases (10-15 hours)
Goals:
- Handle edge cases
- Document the workflow
Tasks:
- Test edge cases from section 3.6
- Write a short summary of decisions
Checkpoint: Edge cases are handled or documented.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Targeting strategy | Search vs find vs motion | Choose the most stable | Stability beats speed early on |
| Repeatability | Dot vs macro | Use dot first | Lower complexity |
| Verification | Visual check vs checklist | Use a checklist | Prevents silent errors |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Manual Checks | Validate edits | Before/after snapshots |
| Repeatability Tests | Ensure dot/macro works | Run on 3+ targets |
| Edge Case Tests | Handle boundary conditions | Missing fields or empty lines |
6.2 Critical Test Cases
- Nominal case: Apply the workflow to a standard line.
- Duplicate target: Handle two targets on the same line.
- Irregular line: Verify behavior when a field is missing.
6.3 Test Data
Use the provided sample input file and create 3 additional lines with variations.
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Over-using Visual mode | Changes are hard to repeat | Use operator + motion |
| Wrong motion choice | Target missed | Use a larger text object |
| No validation step | Silent errors | Use a checklist |
7.2 Debugging Strategies
- Replay slowly: Step through the workflow one command at a time.
- Use undo: Roll back and re-apply with a clearer motion.
7.3 Performance Traps
Overusing j/k on large files instead of search can make the workflow slow.
8. Extensions & Challenges
8.1 Beginner Extensions
- Repeat the workflow on a smaller file
- Document the exact keystroke sequence
8.2 Intermediate Extensions
- Apply the workflow to a real project file
- Reduce keystroke count by 20%
8.3 Advanced Extensions
- Build a macro to automate the workflow
- Create a custom mapping to speed up a frequent step
9. Real-World Connections
9.1 Industry Applications
- Remote server editing: Vim is common on production systems
- Incident response: quick log edits without GUI tools
9.2 Related Open Source Projects
- Vim: core editor reference
- Neovim: modernized modal editor
- Universal Ctags: tag generation tool
9.3 Interview Relevance
- Motion grammar questions
- Repeatability and macro questions
- Command-line editing scenarios
10. Resources
10.1 Essential Reading
- “Practical Vim” by Drew Neil - focus on motion and change workflows
- “Learning the vi and Vim Editors” - foundational navigation
10.2 Video Resources
- “Vim as a Language” talk (searchable title)
- “Practical Vim” author talks (searchable title)