Using Cursor AI as Part of Your Development Workflow
We know that AI is good at code completion. But how is it as part of a normal development flow? We put Cursor through its paces.
Sep 14th, 2024 4:11am by
Image via Unsplash+.
High Score
I’m going to develop a simple High Score table in C#. All this does is receive scores from various games, then displays the scores for a given game, in order.- I will write the code (separately from Cursor) and ask Cursor to summarize what it does.
- I will ask it to spot a bug that I will leave in it.
- I will add the ability to remove a particular score and see how it makes suggestions.
- I will then ask it to create some unit tests.
using System;
using System.Collections.Generic;
User tim = new ("12345","Timbo");
User jim = new ("45123","Jimbo");
User kim = new ("6534", "Kimbo");
TopScore ts = new TopScore();
ts.AddScore(Score.RegisteredGame.MatterBlatter, tim, 1000, "Level 3");
ts.AddScore(Score.RegisteredGame.MatterBlatter, tim, 1200, "Level 4");
ts.AddScore(Score.RegisteredGame.MasterBlaster, jim, 1000, "HellGate");
ts.AddScore(Score.RegisteredGame.MasterBlaster, tim, 1200, "FinalBoss");
ts.AddScore(Score.RegisteredGame.MatterBlatter, kim, 1000, "Level 3");
ts.AddScore(Score.RegisteredGame.MatterBlatter, kim, 3200, "Level 5");
List<string> topscores = ts.FormattedTopScoreTable(Score.RegisteredGame.MatterBlatter);
Console.WriteLine($"TOP SCORES FOR {Score.RegisteredGame.MatterBlatter}");
topscores.ForEach(sc => Console.WriteLine(sc));
public struct User {
public string PlayerId;
public string KnownAs;
public User(string playerId, string knownAs) {
PlayerId = playerId;
KnownAs = knownAs;
}
}
public class Score : IComparable<Score> {
public enum RegisteredGame { MatterBlatter, MasterBlaster, MinionPinion}
public DateTime Entrydate;
public int ScoreValue;
public string Level = "";
public RegisteredGame Game;
public User Player;
public int CompareTo(Score? other) {
return (other.ScoreValue - ScoreValue);
}
public Score(RegisteredGame registeredGame, User player, int scoreValue, string level = "") {
Game = registeredGame;
Entrydate = DateTime.Now;
ScoreValue = scoreValue;
Level = level;
Player = player;
}
}
public class TopScore {
private List<Score> scores = new List<Score>();
const short TABLESIZE = 10;
public void AddScore(Score.RegisteredGame registeredGame, User user, int scorevalue, string level)
{
Score score = new (registeredGame, user, scorevalue, level);
scores.Add(score);
}
public List<string> FormattedTopScoreTable(Score.RegisteredGame registeredGame) {
List<string> toptable = new List<string>();
//First sort
List<Score> justOnegame = scores.FindAll(sc => sc.Game == registeredGame);
justOnegame.Sort();
//Grab subset
List<Score> topItems = (justOnegame.Count < TABLESIZE)?justOnegame:(List<Score>)justOnegame.Take(TABLESIZE);
topItems.ForEach(sc => toptable.Add($"{sc.ScoreValue} {sc.Player.KnownAs} ({sc.Level})"));
return toptable;
}
}
… which is in the wrong order for a High Score table.
Just pressing the “Download for Free” button on the main page downloaded build version 0.40.4 of Cursor. As you would if you were starting an existing project with VS Code, it is best to run Cursor from the command line, within the root folder, so that it picks up the context in your shell. To help, you may want to open the Command Palette and use Shell Command: Install 'cursor' command.
Unfortunately, you cannot actually run a .NET program and debug it in Cursor, because Microsoft blocks it. If Cursor was a plugin to VS Code, all would be fine, but as it is a fork, Microsoft doesn’t recognize it. I’m sure this will be resolved before long, but right now it means you need to keep VS Code open to run the code.
First, the summary. After bringing up the chat sidebar (which correctly doesn’t appear unless you ask for it), I asked Claude 3.5 Sonnet to “summarize the code.” Here are the highlights:
1. The code defines a simple game-scoring system with three main classes/structs:
- `User`: Represents a player with an ID and name.
- `Score`: Represents a game score with details like game type, player, score value, and level.
- `TopScore`: Manages a list of scores and provides methods to add scores and generate formatted top score tables.
- `AddScore`: Adds a new score to the list.
- `FormattedTopScoreTable`: Generates a formatted list of top scores for a specific game type.
public List<string> FormattedTopScoreTable(Score.RegisteredGame registeredGame) {
// ... existing code ...
justOnegame.Sort();
//Grab subset
List<Score> topItems = (justOnegame.Count < TABLESIZE)?justOnegame:(List<Score>)justOnegame.Take(TABLESIZE);
// ... existing code ...
}
- The
Sort()method is called on the list, but it’s sorting in ascending order (lowest to highest) because of howCompareTois implemented in theScoreclass. - The
Take(TABLESIZE)method is then used to select the top items, but it’s actually selecting the lowest scores instead of the highest.
-
- Reverse the comparison in the
CompareTomethod of theScoreclass. - Use
OrderByDescendinginstead ofSort()in theFormattedTopScoreTablemethod.
- Reverse the comparison in the
OK, so I have discovered subsequently that Kim has been cheating, so I want to remove all of her scores from the list. We’ll call it “PurgeUser” on the top score list.
I ask in the chat, “How can I write a PurgeUser method, to remove all the scores from a certain user?”
The method is given:
public void PurgeUser(User user) {
scores.RemoveAll(score => score.Player.PlayerId == user.PlayerId);
}
ts.PurgeUser(userToPurge);
“Note: This method assumes that PlayerId is unique for each user.”
An obvious point, but I like the fact it mentioned this as part of its assumptions. It understood that I might have just used a pattern without being aware of an underlying necessity.
Purging Kim works just fine. Finally I asked it to suggest unit tests — I previously did this with Codium. These were all done comprehensively, but here is one example:
[Test]
public void AddScore_AddsScoreCorrectly() {
topScore.AddScore(Score.RegisteredGame.MatterBlatter, user1, 1000, "Level 1");
var scores = topScore.FormattedTopScoreTable(Score.RegisteredGame.MatterBlatter);
Assert.AreEqual(1, scores.Count);
Assert.AreEqual("1000 Alice (Level 1)", scores[0]);
}
It then checked that I wanted to do this. Then it lets you push the diffs over to your open code file. (Actually this didn’t work in my case; tests should be placed in a separate file)
Conclusion
I like the way Cursor places any code mentioned within the chat channel inside separate panels that can later be integrated via diffs to your code. This feels like the right way to do things. It also did work very quickly and made autocompletion suggestions smartly. Overall, Cursor has gone down the route of “tool,” not “seer.” This gives me much more confidence that Cursor is taking part in your workflow, not trying to replace it. I think how it continues to work with VS Code will determine future success. It seems more than possible that Microsoft will collaborate with Cursor to try to bring more success to the AI-powered coding world.
YOUTUBE.COM/THENEWSTACK
Tech moves fast, don't miss an episode. Subscribe to our YouTube
channel to stream all our podcasts, interviews, demos, and more.