Cursor

AI開発支援コードエディタVS CodeマルチモデルGPT-4ClaudeGemini

AIツール

Cursor

概要

CursorはVS Codeをベースに構築されたAI統合コードエディターです。プラグイン形式ではなく、エディター自体にAI機能を深く組み込んでおり、複数の最新AIモデル(Claude 4、GPT-4.1、Gemini 2.5等)を活用したコード生成・編集が可能です。VS Codeの完全フォーク版として開発されているため、既存のワークスペースをそのまま使用でき、拡張機能の大部分も互換性があります。

詳細

Cursorは2023年3月にリリースされたAI統合エディターで、スタートアップ業界を中心に急速に普及しています。VS Codeのフォーク版として開発されることで、プラグインでは実現できない深いAI統合を可能にしています。リアルタイムプロジェクトインデックス、自然言語によるコード操作、複数ファイル対応のAI編集など、従来のAI支援ツールを大きく上回る機能を提供します。

主要AI機能

  • Ctrl+K機能: コード内で直接編集指示を行い、AIが修正を適用
  • AI Chat: プロジェクト理解型の対話機能(Ctrl/⌘ + L)
  • Agent/Composer機能: 複数ファイルにわたるコード生成と変更
  • Tab補完: VS Codeより高速で精度の高いコード補完
  • 自動修正: Ctrl/⌘ + Shift + EによるAI自動修正
  • @メンション機能: @ファイル名やURLでコンテキスト指定

対応AIモデル(2024年版)

  • Claude 4 Opus: 最先端のコーディングモデル
  • GPT-4.1: OpenAIの最新モデル
  • Claude 3.5 Sonnet: バランスの取れた性能
  • Gemini 2.5 Pro: Googleの最新モデル
  • o1、o3-pro: 推論特化モデル
  • DeepSeek、Grok: その他の先進モデル

メリット・デメリット

メリット

  • 開発効率の大幅向上: 従来比30%の開発速度向上を実現
  • 高度なAI統合: プロジェクト全体のコンテキスト理解とリアルタイムインデックス
  • VS Code互換性: 既存のワークスペースと拡張機能がそのまま利用可能
  • マルチモデル対応: 複数の最新AIモデルから最適なものを選択可能
  • プライバシー対応: プライバシーモードとSOC 2認証によるセキュリティ保証
  • 直感的なUI: VS Codeライクな慣れ親しんだインターフェース

デメリット

  • 高額なコスト: Pro版$20/月(GitHub Copilot $10/月の2倍)
  • 複雑なUI: 多機能による画面の煩雑さとAI提案の重複表示
  • 大規模プロジェクト: 巨大なコードベースでの性能低下が発生する場合
  • AIコード品質: 生成されるコードの品質にばらつきがある
  • VS Codeアップデート: 手動統合のため新機能の取り込みに遅延が発生

参考ページ

書き方の例

インストールとセットアップ

# 公式サイトからダウンロードしてインストール
# https://cursor.com/

# VS Codeからの設定移行(自動実行)
# 既存のワークスペース、拡張機能、設定が自動的にインポート

# 初回起動時のAI機能設定
# 使用するAIモデルの選択
# プライバシー設定の確認

基本的なAI機能の使用

// Ctrl+K機能の使用例
// 以下のコードを選択してCtrl+Kを押し、指示を入力

function calculateTotal(items) {
    // "TypeScriptの型定義を追加して、エラーハンドリングも含めて"
}

// AIが以下のような修正を提案
interface Item {
    id: string;
    name: string;
    price: number;
    quantity: number;
}

function calculateTotal(items: Item[]): number {
    try {
        if (!Array.isArray(items) || items.length === 0) {
            return 0;
        }
        
        return items.reduce((total, item) => {
            if (typeof item.price !== 'number' || typeof item.quantity !== 'number') {
                throw new Error(`Invalid item data: ${item.name}`);
            }
            return total + (item.price * item.quantity);
        }, 0);
    } catch (error) {
        console.error('Error calculating total:', error);
        return 0;
    }
}

AI Chat機能の活用

// Ctrl/⌘ + L でAIチャットを開く
// @記号でファイルやURLを指定してコンテキストを提供

/*
チャット例:
"@components/UserProfile.tsx を見て、プロフィール編集機能を追加してください。
編集フォームにはバリデーションとエラーハンドリングを含めてください。"
*/

// AI Chatの回答に基づいた実装例
import React, { useState, useEffect } from 'react';
import { User, ValidationError } from '@/types';

interface UserProfileEditProps {
    user: User;
    onSave: (user: User) => Promise<void>;
    onCancel: () => void;
}

export const UserProfileEdit: React.FC<UserProfileEditProps> = ({
    user,
    onSave,
    onCancel
}) => {
    const [formData, setFormData] = useState<User>(user);
    const [errors, setErrors] = useState<Record<string, string>>({});
    const [isLoading, setIsLoading] = useState(false);

    const validateForm = (): boolean => {
        const newErrors: Record<string, string> = {};
        
        if (!formData.name.trim()) {
            newErrors.name = '名前は必須です';
        }
        
        if (!formData.email.trim()) {
            newErrors.email = 'メールアドレスは必須です';
        } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
            newErrors.email = '有効なメールアドレスを入力してください';
        }
        
        setErrors(newErrors);
        return Object.keys(newErrors).length === 0;
    };

    const handleSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        
        if (!validateForm()) return;
        
        setIsLoading(true);
        try {
            await onSave(formData);
        } catch (error) {
            setErrors({ submit: 'プロフィールの更新に失敗しました' });
        } finally {
            setIsLoading(false);
        }
    };

    return (
        <form onSubmit={handleSubmit} className="user-profile-edit">
            <div className="form-group">
                <label htmlFor="name">名前</label>
                <input
                    id="name"
                    value={formData.name}
                    onChange={(e) => setFormData({ ...formData, name: e.target.value })}
                    className={errors.name ? 'error' : ''}
                />
                {errors.name && <span className="error-text">{errors.name}</span>}
            </div>
            
            <div className="form-group">
                <label htmlFor="email">メールアドレス</label>
                <input
                    id="email"
                    type="email"
                    value={formData.email}
                    onChange={(e) => setFormData({ ...formData, email: e.target.value })}
                    className={errors.email ? 'error' : ''}
                />
                {errors.email && <span className="error-text">{errors.email}</span>}
            </div>
            
            {errors.submit && <div className="error-text">{errors.submit}</div>}
            
            <div className="form-actions">
                <button type="button" onClick={onCancel} disabled={isLoading}>
                    キャンセル
                </button>
                <button type="submit" disabled={isLoading}>
                    {isLoading ? '保存中...' : '保存'}
                </button>
            </div>
        </form>
    );
};

Composer/Agent機能の活用

// Composer機能での複数ファイル生成指示例
/*
"ECサイトの商品管理システムを作成してください。以下のファイルを生成してください:
1. Product型定義(types/Product.ts)
2. ProductAPIクライアント(api/products.ts)  
3. ProductList コンポーネント(components/ProductList.tsx)
4. ProductForm コンポーネント(components/ProductForm.tsx)
5. 商品管理ページ(pages/ProductsPage.tsx)

React + TypeScript + Tailwind CSSを使用してください。"
*/

// 自動生成される types/Product.ts
export interface Product {
    id: string;
    name: string;
    description: string;
    price: number;
    category: string;
    imageUrl: string;
    stock: number;
    isActive: boolean;
    createdAt: Date;
    updatedAt: Date;
}

export interface CreateProductDto {
    name: string;
    description: string;
    price: number;
    category: string;
    imageUrl: string;
    stock: number;
}

export interface UpdateProductDto extends Partial<CreateProductDto> {
    isActive?: boolean;
}

// 自動生成される api/products.ts
import { Product, CreateProductDto, UpdateProductDto } from '@/types/Product';

class ProductAPI {
    private baseUrl = '/api/products';

    async getProducts(): Promise<Product[]> {
        const response = await fetch(this.baseUrl);
        if (!response.ok) throw new Error('Failed to fetch products');
        return response.json();
    }

    async getProduct(id: string): Promise<Product> {
        const response = await fetch(`${this.baseUrl}/${id}`);
        if (!response.ok) throw new Error('Failed to fetch product');
        return response.json();
    }

    async createProduct(product: CreateProductDto): Promise<Product> {
        const response = await fetch(this.baseUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(product)
        });
        if (!response.ok) throw new Error('Failed to create product');
        return response.json();
    }

    async updateProduct(id: string, product: UpdateProductDto): Promise<Product> {
        const response = await fetch(`${this.baseUrl}/${id}`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(product)
        });
        if (!response.ok) throw new Error('Failed to update product');
        return response.json();
    }

    async deleteProduct(id: string): Promise<void> {
        const response = await fetch(`${this.baseUrl}/${id}`, {
            method: 'DELETE'
        });
        if (!response.ok) throw new Error('Failed to delete product');
    }
}

export const productAPI = new ProductAPI();

プライバシー設定とカスタマイズ

// .cursor/settings.json
{
  "cursor.general.privacyMode": true,
  "cursor.general.disableHttp2": true,
  "cursor.ai.models": ["claude-4", "gpt-4.1", "gemini-2.5-pro"],
  "cursor.ai.defaultModel": "claude-4",
  "cursor.ai.maxTokens": 4000,
  "cursor.ai.temperature": 0.2
}

// .cursorignore ファイル設定
node_modules/
.env
*.log
dist/
build/
.secrets/
config.json
*.key
*.pem

VS Codeからの移行手順

# 1. 現在のVS Code設定のバックアップ
cp -r ~/.vscode/extensions ~/.vscode/extensions.backup
cp ~/.vscode/settings.json ~/.vscode/settings.backup.json

# 2. Cursorのダウンロードとインストール
# https://cursor.com/ からダウンロード

# 3. 初回起動時の自動移行
# - 設定の自動インポート
# - 拡張機能の互換性チェック
# - ワークスペースの引き継ぎ

# 4. 学習期間(約2週間)
# - AI機能の段階的活用
# - ショートカットキーの習得
# - ワークフローの最適化