<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>エディタ - CayTech Lab</title>
	<atom:link href="https://caymezon.com/tag/%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF/feed/" rel="self" type="application/rss+xml" />
	<link>https://caymezon.com</link>
	<description></description>
	<lastBuildDate>Sat, 28 Feb 2026 03:46:50 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://caymezon.com/wp-content/uploads/2026/01/cropped-CayTechLab-32x32.jpg</url>
	<title>エディタ - CayTech Lab</title>
	<link>https://caymezon.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<atom:link rel='hub' href='https://caymezon.com/?pushpress=hub'/>
	<item>
		<title>VSCodeで「デリミタ間テキスト選択コピー」を実現するTypeScriptマクロ【括弧・引用符を1キーで抜き出し】</title>
		<link>https://caymezon.com/vscode-delimiter-copy-macro/</link>
					<comments>https://caymezon.com/vscode-delimiter-copy-macro/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Wed, 11 Feb 2026 07:43:41 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[VSCode]]></category>
		<category><![CDATA[エディタ]]></category>
		<category><![CDATA[テキスト編集]]></category>
		<category><![CDATA[マクロ]]></category>
		<category><![CDATA[生産性向上]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20114</guid>

					<description><![CDATA[<p>目次 はじめに：引用符や括弧内のテキスト選択、面倒じゃないですか？この記事で分かること実装した機能の概要できること対応デリミタ（18種類）3つの動作モードフォールバック機能具体的な使用場面とメリット場面1：コード内の文字 [&#8230;]</p>
<p>The post <a href="https://caymezon.com/vscode-delimiter-copy-macro/">VSCodeで「デリミタ間テキスト選択コピー」を実現するTypeScriptマクロ【括弧・引用符を1キーで抜き出し】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに：引用符や括弧内のテキスト選択、面倒じゃないですか？</a></li><li><a href="#toc2" tabindex="0">この記事で分かること</a></li><li><a href="#toc3" tabindex="0">実装した機能の概要</a><ol><li><a href="#toc4" tabindex="0">できること</a></li><li><a href="#toc5" tabindex="0">対応デリミタ（18種類）</a></li><li><a href="#toc6" tabindex="0">3つの動作モード</a></li><li><a href="#toc7" tabindex="0">フォールバック機能</a></li></ol></li><li><a href="#toc8" tabindex="0">具体的な使用場面とメリット</a><ol><li><a href="#toc9" tabindex="0">場面1：コード内の文字列リテラルを抽出</a></li><li><a href="#toc10" tabindex="0">場面2：ファイルパスを素早く抽出</a></li><li><a href="#toc11" tabindex="0">場面3：JSONのキーや値を抽出</a></li><li><a href="#toc12" tabindex="0">場面4：正規表現パターンを抽出</a></li><li><a href="#toc13" tabindex="0">場面5：複雑な入れ子構造から特定部分を抽出</a></li><li><a href="#toc14" tabindex="0">場面6：Markdown内のコード抜き出し</a></li><li><a href="#toc15" tabindex="0">場面7：コピー&貼り付け置換（Ctrl+Alt+Sの活用）</a></li><li><a href="#toc16" tabindex="0">メリットまとめ</a></li></ol></li><li><a href="#toc17" tabindex="0">改修履歴：ネスト構造への対応</a><ol><li><a href="#toc18" tabindex="0">改修前の問題点</a></li><li><a href="#toc19" tabindex="0">改修内容：括弧のバランスを考慮したマッチング</a></li></ol></li><li><a href="#toc20" tabindex="0">TypeScript実装の詳細</a></li><li><a href="#toc21" tabindex="0">コードのポイント解説</a><ol><li><a href="#toc22" tabindex="0">1. デリミタペアの定義</a></li><li><a href="#toc23" tabindex="0">2. コピーと選択の共通化</a></li><li><a href="#toc24" tabindex="0">3. 選択方向の判定</a></li><li><a href="#toc25" tabindex="0">4. 最も近いデリミタの優先</a></li><li><a href="#toc26" tabindex="0">5. デリミタの除外</a></li><li><a href="#toc27" tabindex="0">6. パフォーマンス最適化</a></li><li><a href="#toc28" tabindex="0">7. ネストレベル考慮のアルゴリズム</a></li></ol></li><li><a href="#toc29" tabindex="0">package.jsonの設定</a><ol><li><a href="#toc30" tabindex="0">extension.tsでの登録</a></li></ol></li><li><a href="#toc31" tabindex="0">使い方</a><ol><li><a href="#toc32" tabindex="0">基本的な使い方</a></li><li><a href="#toc33" tabindex="0">コピー&貼り付け置換の使い方</a></li><li><a href="#toc34" tabindex="0">方向別の使い方</a></li></ol></li><li><a href="#toc35" tabindex="0">トラブルシューティング</a><ol><li><a href="#toc36" tabindex="0">Q: デリミタが認識されない</a></li><li><a href="#toc37" tabindex="0">Q: 入れ子構造で意図しない範囲が選択される</a></li><li><a href="#toc38" tabindex="0">Q: 行全体がコピーされてしまう</a></li><li><a href="#toc39" tabindex="0">Q: 動作が遅い</a></li></ol></li><li><a href="#toc40" tabindex="0">パフォーマンスについて</a><ol><li><a href="#toc41" tabindex="0">計算量</a></li><li><a href="#toc42" tabindex="0">ベンチマーク（参考値）</a></li></ol></li><li><a href="#toc43" tabindex="0">拡張アイデア</a><ol><li><a href="#toc44" tabindex="0">カスタムデリミタの設定</a></li><li><a href="#toc45" tabindex="0">複数行対応</a></li></ol></li><li><a href="#toc46" tabindex="0">まとめ：キーボード1回でデリミタ内を抜き出す快適さ</a></li><li><a href="#toc47" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに：引用符や括弧内のテキスト選択、面倒じゃないですか？</span></h2>
<p>VSCodeで文字列編集をしていて、こんな経験はありませんか？</p>
<pre><code class="language-javascript">const message = "このテキストだけコピーしたい";
const path = '/home/user/documents/report.pdf';
const config = { name: "設定値", value: 123 };</code></pre>
<p><strong>ダブルクォーテーション内の文字列だけコピーしたい</strong>ときに、以下のような操作が必要です：</p>
<ol>
<li>マウスで開始位置をクリック</li>
<li>ドラッグして終了位置まで選択</li>
<li>Ctrl+Cでコピー</li>
</ol>
<p>あるいは：</p>
<ol>
<li>Ctrl+Shift+→を何度も押して単語単位で選択</li>
<li>微調整のためにShift+→/←</li>
<li>Ctrl+Cでコピー</li>
</ol>
<p><strong>特に長い文字列や入れ子構造の場合、この作業は非常に煩雑です。</strong></p>
<p>標準のVSCodeには「Ctrl+Shift+→」「Alt+Shift+→」などの単語単位選択機能がありますが、デリミタ（区切り文字）を意識した選択には対応していません。引用符や括弧の中身だけを<strong>1キー操作で選択・コピー</strong>できたら便利だと思いませんか？</p>
<p>そこで、<strong>カーソル位置から自動でデリミタを検索し、その間のテキストを1キーで選択・コピーするTypeScriptマクロを開発しました。</strong></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで (Software Design plus)","b":"技術評論社","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/510GhCOD1FL._SL500_.jpg","\/41og2y1EEHL._SL500_.jpg","\/51XHb97PpFL._SL500_.jpg","\/51uDIY22bQL._SL500_.jpg","\/51PaoVK3MWL._SL500_.jpg","\/51eG7JBoavL._SL500_.jpg","\/51CDCo8FmJL._SL500_.jpg","\/41JLTXb+tsL._SL500_.jpg","\/51Hsv39e7IL._SL500_.jpg","\/41PTe+TqLEL._SL500_.jpg","\/51TUxdoXjrL._SL500_.jpg","\/51AkZEJWGhL._SL500_.jpg","\/51paP7D5R5L._SL500_.jpg","\/41lJtbpaQvL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4297127474","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4297127474","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"OaDLa","s":"s"});</script></p>
<div id="msmaflink-OaDLa">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">この記事で分かること</span></h2>
<ul>
<li>デリミタ間テキスト選択コピーの機能と使い方</li>
<li>対応するデリミタの種類（18種類）</li>
<li>コピーせず選択のみを行う <code>Ctrl+Alt+S</code> の活用法</li>
<li>選択方向による動作の違い（右方向/左方向）</li>
<li>TypeScript実装の詳細コード</li>
<li>実務での活用例とパフォーマンス</li>
</ul>
<h2><span id="toc3">実装した機能の概要</span></h2>
<h3><span id="toc4">できること</span></h3>
<p><strong>2つのショートカットキーで使い分けられます：</strong></p>
<ul>
<li><code>Ctrl+Alt+D</code> : デリミタ間を選択してクリップボードにコピー</li>
<li><code>Ctrl+Alt+S</code> : デリミタ間を選択のみ（クリップボードは変更しない）</li>
</ul>
<p><code>Ctrl+Alt+S</code> は「コピー元でCtrl+Alt+D → 置換先でCtrl+Alt+S → Ctrl+V」という<strong>コピー&貼り付け置換</strong>の用途を想定しています。</p>
<p><strong>Ctrl+Alt+D を押すだけで、カーソル位置の最も近いデリミタ間のテキストを自動選択・コピー</strong></p>
<pre><code class="language-plaintext">例：＜"「あいうえお」、【かきくけこ】、｛さしすせそ｝"＞
          ↑ここにカーソル
          
Ctrl+Alt+D を押す
          
→「あいうえお」だけが選択・コピーされる（引用符は除外）</code></pre>
<h3><span id="toc5">対応デリミタ（18種類）</span></h3>
<h4>クォーテーション・スラッシュ系</h4>
<ul>
<li><code>&quot;～&quot;</code> (ダブルクォート)</li>
<li><code>&#39;～&#39;</code> (シングルクォート)</li>
<li><code>`～`</code> (バッククォート)</li>
<li><code>/～/</code> (スラッシュ・半角)</li>
<li><code>／～／</code> (スラッシュ・全角)</li>
<li><code>\～\</code> (バックスラッシュ・半角)</li>
<li><code>￥～￥</code> (円記号・全角)</li>
<li><code>|～|</code> (パイプ・半角)</li>
<li><code>｜～｜</code> (パイプ・全角)</li>
</ul>
<h4>括弧系（半角・全角）</h4>
<ul>
<li><code>(～)</code> / <code>（～）</code> (丸括弧)</li>
<li><code>[～]</code> (角括弧)</li>
<li><code>{～}</code> / <code>｛～｝</code> (波括弧)</li>
<li><code>&lt;～&gt;</code> / <code>＜～＞</code> (山括弧)</li>
<li><code>【～】</code> (墨付き括弧)</li>
<li><code>「～」</code> (鉤括弧)</li>
</ul>
<h3><span id="toc6">3つの動作モード</span></h3>
<h4>1. 通常モード（カーソル位置から左に検索）</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
       ↑カーソル
       
→ カーソルの左にある最も近い開始デリミタ「"」を検出
→ 対応する終了デリミタ「"」を右に検索
→ 「あいうえお」、【かきくけこ】 が選択される</code></pre>
<h4>2. 右方向モード（1文字選択 + カーソルが右側）</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
   ↑選択    ↑カーソル（左→右に選択）
   
→ 選択文字「"」が開始デリミタか判定
→ 右に終了デリミタ「"」を検索
→ 「あいうえお」、【かきくけこ】 が選択される</code></pre>
<h4>3. 左方向モード（1文字選択 + カーソルが左側）</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
   ↑カーソル ↑選択（右→左に選択）
   
→ 選択文字「"」が終了デリミタか判定
→ 左に開始デリミタ「"」を検索
→ 「あいうえお」、【かきくけこ】 が選択される</code></pre>
<h3><span id="toc7">フォールバック機能</span></h3>
<p>デリミタが見つからない場合は、<strong>行全体をコピー</strong>（<code>Ctrl+Alt+D</code>）または<strong>行全体を選択</strong>（<code>Ctrl+Alt+S</code>）します。</p>
<h2><span id="toc8">具体的な使用場面とメリット</span></h2>
<h3><span id="toc9">場面1：コード内の文字列リテラルを抽出</span></h3>
<pre><code class="language-javascript">const errorMessage = "接続に失敗しました。しばらく経ってから再度お試しください。";</code></pre>
<p>文字列の中にカーソルを置いて<code>Ctrl+Alt+D</code> → 文字列だけが即座にコピーされる。</p>
<p><strong>従来の方法：</strong></p>
<ol>
<li><code>&quot;</code>の直後をクリック</li>
<li>Shift+Endで行末まで選択</li>
<li>Shift+←で<code>&quot;</code>の手前まで調整</li>
<li>Ctrl+C</li>
</ol>
<p><strong>このマクロ：</strong></p>
<ol>
<li>文字列内にカーソルを置く</li>
<li><code>Ctrl+Alt+D</code></li>
</ol>
<p><strong>たった1操作で完了！</strong></p>
<h3><span id="toc10">場面2：ファイルパスを素早く抽出</span></h3>
<pre><code class="language-javascript">const configPath = '/etc/nginx/sites-available/default';
const dataPath = '/var/www/html/data/uploads/2026/02/';</code></pre>
<p>パス内にカーソルを置いて<code>Ctrl+Alt+D</code> → パス全体がコピーされる。</p>
<h3><span id="toc11">場面3：JSONのキーや値を抽出</span></h3>
<pre><code class="language-json">{
  "database": {
    "host": "localhost",
    "port": 5432,
    "name": "production_db"
  }
}</code></pre>
<p>各値にカーソルを置いて<code>Ctrl+Alt+D</code> → 値だけが抽出される。</p>
<h3><span id="toc12">場面4：正規表現パターンを抽出</span></h3>
<pre><code class="language-javascript">const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;</code></pre>
<p>パターン内にカーソルを置いて<code>Ctrl+Alt+D</code> → 正規表現本体だけがコピーされる（<code>/～/</code>を除外）。</p>
<h3><span id="toc13">場面5：複雑な入れ子構造から特定部分を抽出</span></h3>
<h4>異なる種類のデリミタの入れ子</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】、｛さしすせそ｝"＞</code></pre>
<p>この複雑な構造でも：</p>
<ul>
<li><code>「</code>の後にカーソル → <code>あいうえお</code>が選択される</li>
<li><code>【</code>の後にカーソル → <code>かきくけこ</code>が選択される</li>
<li><code>＜</code>の後にカーソル → 最外側の<code>&quot;～&quot;</code>が選択される</li>
</ul>
<p><strong>最も近いデリミタを自動判別</strong>するため、入れ子構造でも正確に動作します。</p>
<h4>同じ種類のデリミタのネスト構造</h4>
<pre><code class="language-javascript">function outer(a, inner(b, c), d)</code></pre>
<p>この場合、カーソルが<code>outer</code>にあるとき：</p>
<ul>
<li>左で最も近い<code>(</code>（<code>outer</code>の後）を検出</li>
<li>ネストレベルを考慮して対応する<code>)</code>を検索</li>
<li>内側の<code>inner(b, c)</code>のネストをカウント</li>
<li><strong><code>a, inner(b, c), d</code>全体が正確に選択される</strong> ✅</li>
</ul>
<p>従来バージョンでは誤って<code>outer(a, inner(b, c</code>が選択されていましたが、ネスト対応により正確に動作するようになりました。</p>
<h3><span id="toc14">場面6：Markdown内のコード抜き出し</span></h3>
<pre><code class="language-markdown">インラインコードは`console.log('Hello')`のように書きます。</code></pre>
<p>バッククォート内にカーソルを置いて<code>Ctrl+Alt+D</code> → <code>console.log(&#39;Hello&#39;)</code>だけがコピーされる。</p>
<h3><span id="toc15">場面7：コピー&貼り付け置換（Ctrl+Alt+Sの活用）</span></h3>
<p><code>Ctrl+Alt+S</code>（選択のみ）との組み合わせで、<strong>貼り付けによる置換</strong>が手軽にできます。</p>
<pre><code class="language-javascript">const oldValue = "置換前の文字列";
const newValue = "置換後の文字列";</code></pre>
<p><strong>手順：</strong></p>
<ol>
<li><code>&quot;置換前の文字列&quot;</code> 内にカーソル → <code>Ctrl+Alt+D</code> でコピー</li>
<li><code>&quot;置換後の文字列&quot;</code> 内にカーソルを移動</li>
<li><code>Ctrl+Alt+S</code> で置換対象を選択</li>
<li><code>Ctrl+V</code> で貼り付け → 置換完了！</li>
</ol>
<p>クリップボードを変更せずに置換先だけを選択できるので、途中でクリップボードが上書きされる心配がありません。</p>
<h3><span id="toc16">メリットまとめ</span></h3>
<ul>
<li><strong>マウス操作不要</strong>: カーソル位置だけで判定</li>
<li><strong>高速</strong>: キーボード1回で完結</li>
<li><strong>正確</strong>: デリミタを自動検出</li>
<li><strong>柔軟</strong>: 選択方向で動作を変更可能、コピー/選択を使い分け可能</li>
<li><strong>安全</strong>: デリミタが見つからなくても行全体をコピー/選択</li>
</ul>
<h2><span id="toc17">改修履歴：ネスト構造への対応</span></h2>
<h3><span id="toc18">改修前の問題点</span></h3>
<p>初期バージョンでは、ネスト（入れ子）構造の括弧を正しく処理できない問題がありました。</p>
<p><strong>問題の例：</strong></p>
<pre><code class="language-javascript">function(b,c){...}</code></pre>
<p>この場合、カーソルが<code>function</code>にあるとき：</p>
<ol>
<li>左から最も近い開始デリミタ<code>(</code>を検出</li>
<li>その位置から右に最初に見つかった終了デリミタ<code>)</code>をマッチング</li>
<li>しかし、最初の<code>)</code>は<code>b,c)</code>の閉じ括弧なので、<strong><code>function(b,c</code>が誤って選択される</strong> ❌</li>
</ol>
<p>ネストレベルを考慮していないため、入れ子構造で誤動作していました。</p>
<h3><span id="toc19">改修内容：括弧のバランスを考慮したマッチング</span></h3>
<p>VSCodeの<code>Ctrl+Shift+\</code>（対応する括弧へジャンプ）と同じように、<strong>ネストレベルをカウントしながら対応する括弧を探す</strong>アルゴリズムを実装しました。</p>
<p><strong>アルゴリズム：</strong></p>
<ol>
<li>カーソル位置から左に開始デリミタを検索</li>
<li>その位置から右に向かって：
<ul>
<li>同じ開始デリミタが出現 → カウンタ +1（ネストが深くなる）</li>
<li>対応する終了デリミタが出現 → カウンタ -1（ネストから抜ける）</li>
<li><strong>カウンタが 0 になった位置が対応する終了デリミタ</strong> ✅</li>
</ul>
</li>
</ol>
<p><strong>追加した関数：</strong></p>
<ul>
<li><code>findMatchingEndDelimiter()</code> - 順方向のネスト対応マッチング</li>
<li><code>findMatchingStartDelimiter()</code> - 逆方向のネスト対応マッチング</li>
</ul>
<p>これにより、複雑な入れ子構造でも正確にデリミタのペアを検出できるようになりました。</p>
<h2><span id="toc20">TypeScript実装の詳細</span></h2>
<p>実際のコードを紹介します。<code>copyTextBetweenDelimiters.ts</code>ファイルに実装しました。</p>
<pre><code class="language-typescript">import * as vscode from 'vscode';

/**
 * デリミタペアの定義（開始文字と終了文字）
 */
const DELIMITER_PAIRS: Array&lt;{ start: string; end: string }&gt; = [
    { start: '"', end: '"' },
    { start: "'", end: "'" },
    { start: '`', end: '`' }, // バッククォート（テンプレートリテラル・Markdownインラインコード）
    { start: '/', end: '/' },
    { start: '／', end: '／' },
    { start: '\\', end: '\\' },
    { start: '￥', end: '￥' },
    { start: '|', end: '|' },
    { start: '｜', end: '｜' },
    { start: '「', end: '」' },
    { start: '[', end: ']' },
    { start: '【', end: '】' },
    { start: '{', end: '}' },
    { start: '｛', end: '｝' },
    { start: '(', end: ')' },
    { start: '（', end: '）' },
    { start: '&lt;', end: '&gt;' },
    { start: '＜', end: '＞' }
];

/**
 * デリミタで囲まれたテキストを選択してコピー（デリミタは除外）
 * - カーソル位置から左に開始デリミタを検索
 * - 対応する終了デリミタを右に検索
 * - 見つからない場合は行全体をコピー
 * - 1文字選択時はカーソル位置（選択方向）で動作を変更
 */
export async function copyTextBetweenDelimiters() {
    await processTextBetweenDelimiters(true); // 選択＋コピー
}

/**
 * デリミタで囲まれたテキストを選択するだけ（コピーしない）
 * - copyTextBetweenDelimiters と同じ検索ロジック
 * - 貼り付け先を選択してから Ctrl+V で置換する用途を想定
 */
export async function selectTextBetweenDelimiters() {
    await processTextBetweenDelimiters(false); // 選択のみ
}

/**
 * デリミタ間テキストの共通処理
 * @param copyToClipboard true=選択＋コピー、false=選択のみ
 */
async function processTextBetweenDelimiters(copyToClipboard: boolean) {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        vscode.window.showWarningMessage('アクティブなエディタがありません');
        return;
    }

    const document = editor.document;
    const selection = editor.selection;
    const cursorPos = selection.active;
    const line = document.lineAt(cursorPos.line);
    const lineText = line.text;

    // 1文字選択時の特殊処理（選択方向で動作を変更）
    if (!selection.isEmpty &amp;&amp; selection.end.character - selection.start.character === 1) {
        const selectedChar = lineText[selection.start.character];
        const charPos = selection.start.character;

        // カーソルが選択文字の右側（左→右選択）
        if (selection.active.character &gt; selection.anchor.character) {
            const result = handleRightDirection(lineText, charPos, selectedChar);
            if (result) {
                await applyResult(editor, cursorPos.line, result.start, result.end, copyToClipboard);
                return;
            }
        }
        // カーソルが選択文字の左側（右→左選択）
        else if (selection.active.character &lt; selection.anchor.character) {
            const result = handleLeftDirection(lineText, charPos, selectedChar);
            if (result) {
                await applyResult(editor, cursorPos.line, result.start, result.end, copyToClipboard);
                return;
            }
        }
    }

    // 通常処理：カーソル位置から左に開始デリミタを検索
    const result = findDelimitedText(lineText, cursorPos.character);

    if (result) {
        await applyResult(editor, cursorPos.line, result.start, result.end, copyToClipboard);
    } else {
        // 見つからない場合は行全体を対象
        if (copyToClipboard) {
            copyEntireLine(editor, cursorPos.line);
        } else {
            selectEntireLine(editor, cursorPos.line);
        }
    }
}

/**
 * 右方向処理：選択文字が開始デリミタかチェックし、右に終了デリミタを検索（ネスト考慮）
 */
function handleRightDirection(
    lineText: string,
    charPos: number,
    selectedChar: string
): { start: number; end: number } | null {
    for (const pair of DELIMITER_PAIRS) {
        if (selectedChar === pair.start) {
            // ネストレベルを考慮して対応する終了デリミタを検索
            const endPos = findMatchingEndDelimiter(lineText, charPos, pair.start, pair.end);
            if (endPos !== -1) {
                // デリミタを除外: 開始の次の文字から終了の前まで
                return { start: charPos + 1, end: endPos };
            }
        }
    }
    return null;
}

/**
 * 左方向処理：選択文字が終了デリミタかチェックし、左に開始デリミタを検索（ネスト考慮）
 */
function handleLeftDirection(
    lineText: string,
    charPos: number,
    selectedChar: string
): { start: number; end: number } | null {
    for (const pair of DELIMITER_PAIRS) {
        if (selectedChar === pair.end) {
            // ネストレベルを考慮して対応する開始デリミタを検索
            const startPos = findMatchingStartDelimiter(lineText, charPos, pair.start, pair.end);
            if (startPos !== -1) {
                // デリミタを除外: 開始の次の文字から終了の前まで
                return { start: startPos + 1, end: charPos };
            }
        }
    }
    return null;
}

/**
 * カーソル位置からデリミタで囲まれたテキストを検索（デリミタは除外）
 * - 左に開始デリミタを検索
 * - ネストレベルを考慮して対応する終了デリミタを右に検索
 */
function findDelimitedText(
    lineText: string,
    cursorPos: number
): { start: number; end: number } | null {
    let bestMatch: { start: number; end: number; startPos: number } | null = null;

    // 各デリミタペアについて検索
    for (const pair of DELIMITER_PAIRS) {
        // カーソル位置の左側で最後に出現する開始デリミタを検索
        let startPos = -1;
        for (let i = cursorPos - 1; i &gt;= 0; i--) {
            if (lineText[i] === pair.start) {
                startPos = i;
                break;
            }
        }

        if (startPos === -1) {
            continue; // 開始デリミタが見つからない
        }

        // 対応する終了デリミタを検索（ネストレベルを考慮）
        const endPos = findMatchingEndDelimiter(lineText, startPos, pair.start, pair.end);

        if (endPos !== -1) {
            // カーソル位置が範囲内にあるかチェック
            if (startPos &lt; cursorPos &amp;&amp; cursorPos &lt;= endPos) {
                // より近い開始デリミタを優先
                if (!bestMatch || startPos &gt; bestMatch.startPos) {
                    // デリミタを除外: 開始の次の文字から終了の前まで
                    bestMatch = {
                        start: startPos + 1,
                        end: endPos,
                        startPos: startPos
                    };
                }
            }
        }
    }

    if (bestMatch) {
        return { start: bestMatch.start, end: bestMatch.end };
    }

    return null;
}

/**
 * ネストレベルを考慮して対応する終了デリミタを検索
 */
function findMatchingEndDelimiter(
    lineText: string,
    startPos: number,
    startDelimiter: string,
    endDelimiter: string
): number {
    // 開始と終了が同じ文字の場合（" や ' など）は従来の方式
    if (startDelimiter === endDelimiter) {
        return lineText.indexOf(endDelimiter, startPos + 1);
    }

    // 異なる文字の場合はネストレベルを考慮
    let nestLevel = 1; // 開始デリミタを見つけた状態から開始

    for (let i = startPos + 1; i &lt; lineText.length; i++) {
        const char = lineText[i];

        if (char === startDelimiter) {
            nestLevel++; // 同じ開始デリミタが出現したらネストレベル+1
        } else if (char === endDelimiter) {
            nestLevel--; // 終了デリミタが出現したらネストレベル-1

            if (nestLevel === 0) {
                return i; // ネストレベルが0になったら対応する終了デリミタを発見
            }
        }
    }

    return -1; // 対応する終了デリミタが見つからない
}

/**
 * ネストレベルを考慮して対応する開始デリミタを検索（逆方向）
 */
function findMatchingStartDelimiter(
    lineText: string,
    endPos: number,
    startDelimiter: string,
    endDelimiter: string
): number {
    // 開始と終了が同じ文字の場合（" や ' など）は従来の方式
    if (startDelimiter === endDelimiter) {
        return lineText.lastIndexOf(startDelimiter, endPos - 1);
    }

    // 異なる文字の場合はネストレベルを考慮（逆方向）
    let nestLevel = 1; // 終了デリミタを見つけた状態から開始

    for (let i = endPos - 1; i &gt;= 0; i--) {
        const char = lineText[i];

        if (char === endDelimiter) {
            nestLevel++; // 同じ終了デリミタが出現したらネストレベル+1
        } else if (char === startDelimiter) {
            nestLevel--; // 開始デリミタが出現したらネストレベル-1

            if (nestLevel === 0) {
                return i; // ネストレベルが0になったら対応する開始デリミタを発見
            }
        }
    }

    return -1; // 対応する開始デリミタが見つからない
}

/**
 * 指定範囲を選択し、copyToClipboard=true の場合はコピーも行う
 */
async function applyResult(
    editor: vscode.TextEditor,
    line: number,
    startChar: number,
    endChar: number,
    copyToClipboard: boolean
) {
    const startPos = new vscode.Position(line, startChar);
    const endPos = new vscode.Position(line, endChar);
    editor.selection = new vscode.Selection(startPos, endPos);
    if (copyToClipboard) {
        await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
    }
}

/**
 * 行全体をクリップボードにコピー
 */
async function copyEntireLine(editor: vscode.TextEditor, lineNumber: number) {
    const line = editor.document.lineAt(lineNumber);
    editor.selection = new vscode.Selection(line.range.start, line.range.end);
    await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
    vscode.window.showInformationMessage('デリミタが見つからないため、行全体をコピーしました');
}

/**
 * 行全体を選択するだけ（コピーしない）
 */
function selectEntireLine(editor: vscode.TextEditor, lineNumber: number) {
    const line = editor.document.lineAt(lineNumber);
    editor.selection = new vscode.Selection(line.range.start, line.range.end);
    vscode.window.showInformationMessage('デリミタが見つからないため、行全体を選択しました');
}</code></pre>
<h2><span id="toc21">コードのポイント解説</span></h2>
<h3><span id="toc22">1. デリミタペアの定義</span></h3>
<pre><code class="language-typescript">const DELIMITER_PAIRS: Array&lt;{ start: string; end: string }&gt; = [
    { start: '"', end: '"' },
    { start: "'", end: "'" },
    { start: '`', end: '`' }, // バッククォート（テンプレートリテラル・Markdownインラインコード）
    { start: '「', end: '」' },
    // ... 18種類
];</code></pre>
<p>開始文字と終了文字のペアを配列で管理。拡張が容易な設計です。</p>
<h3><span id="toc23">2. コピーと選択の共通化</span></h3>
<pre><code class="language-typescript">// コピーする場合（Ctrl+Alt+D）
export async function copyTextBetweenDelimiters() {
    await processTextBetweenDelimiters(true);
}

// 選択のみの場合（Ctrl+Alt+S）
export async function selectTextBetweenDelimiters() {
    await processTextBetweenDelimiters(false);
}

// 共通処理（copyToClipboard で動作を分岐）
async function processTextBetweenDelimiters(copyToClipboard: boolean) {
    // ...
    await applyResult(editor, line, start, end, copyToClipboard);
}</code></pre>
<p><code>copyToClipboard</code>フラグ1つで2つのコマンドを共通化。検索ロジックの重複をなくし、保守性を高めています。</p>
<h3><span id="toc24">3. 選択方向の判定</span></h3>
<pre><code class="language-typescript">// カーソルが選択文字の右側（左→右選択）
if (selection.active.character &gt; selection.anchor.character) {
    // 右方向処理
}
// カーソルが選択文字の左側（右→左選択）
else if (selection.active.character &lt; selection.anchor.character) {
    // 左方向処理
}</code></pre>
<p>VSCodeの<code>selection.active</code>（カーソル位置）と<code>selection.anchor</code>（選択開始位置）を比較して選択方向を判定。</p>
<h3><span id="toc25">4. 最も近いデリミタの優先</span></h3>
<pre><code class="language-typescript">// より近い開始デリミタを優先
if (!bestMatch || startPos &gt; bestMatch.startPos) {
    bestMatch = {
        start: startPos + 1,
        end: endPos,
        startPos: startPos
    };
}</code></pre>
<p>複数のデリミタペアが見つかった場合、カーソルに最も近い開始デリミタを優先します。</p>
<h3><span id="toc26">5. デリミタの除外</span></h3>
<pre><code class="language-typescript">// デリミタを除外: 開始の次の文字から終了の前まで
return { start: charPos + 1, end: endPos };</code></pre>
<p>開始デリミタの<strong>次の文字</strong>から終了デリミタの<strong>前まで</strong>を選択範囲とすることで、デリミタ自体を除外します。</p>
<h3><span id="toc27">6. パフォーマンス最適化</span></h3>
<pre><code class="language-typescript">// 行内のみの線形検索
for (let i = cursorPos - 1; i &gt;= 0; i--) {
    if (lineText[i] === pair.start) {
        startPos = i;
        break;
    }
}</code></pre>
<p><strong>行内のみ</strong>を検索対象とすることで、長大なファイルでもパフォーマンスに影響しません。</p>
<h3><span id="toc28">7. ネストレベル考慮のアルゴリズム</span></h3>
<pre><code class="language-typescript">function findMatchingEndDelimiter(lineText: string, startPos: number, startDelimiter: string, endDelimiter: string): number {
    // 開始と終了が同じ文字（" や ' など）は従来の方式
    if (startDelimiter === endDelimiter) {
        return lineText.indexOf(endDelimiter, startPos + 1);
    }

    // 異なる文字の場合はネストレベルを考慮
    let nestLevel = 1; // 開始デリミタを見つけた状態から開始

    for (let i = startPos + 1; i &lt; lineText.length; i++) {
        const char = lineText[i];

        if (char === startDelimiter) {
            nestLevel++; // 同じ開始デリミタが出現 → ネスト +1
        } else if (char === endDelimiter) {
            nestLevel--; // 終了デリミタが出現 → ネスト -1

            if (nestLevel === 0) {
                return i; // ネストレベルが0 → 対応する括弧を発見
            }
        }
    }

    return -1; // 対応する終了デリミタが見つからない
}</code></pre>
<p><strong>ポイント：</strong></p>
<ul>
<li><code>nestLevel = 1</code> から開始（開始デリミタを見つけた状態）</li>
<li>同じ開始デリミタが出現するたびに <code>nestLevel++</code>（ネストが深くなる）</li>
<li>終了デリミタが出現するたびに <code>nestLevel--</code>（ネストから抜ける）</li>
<li><code>nestLevel === 0</code> になった位置が<strong>対応する終了デリミタ</strong></li>
</ul>
<p><strong>具体例：</strong></p>
<pre><code class="language-javascript">function(a, (b, c), d)
        ↑開始</code></pre>
<ol>
<li><code>function(</code> → <code>nestLevel = 1</code></li>
<li><code>(b</code> → <code>nestLevel = 2</code>（ネストが深くなる）</li>
<li><code>c)</code> → <code>nestLevel = 1</code>（ネストから抜ける）</li>
<li><code>d)</code> → <code>nestLevel = 0</code> ✅ <strong>ここが対応する閉じ括弧</strong></li>
</ol>
<p>これにより、複雑な入れ子構造でも正確にペアを検出できます。</p>
<h2><span id="toc29">package.jsonの設定</span></h2>
<p>拡張機能のコマンドとキーバインディングを登録します。</p>
<pre><code class="language-json">{
  "contributes": {
    "commands": [
      {
        "command": "myMacros.copyTextBetweenDelimiters",
        "title": "Copy Text Between Delimiters",
        "category": "My Macros"
      },
      {
        "command": "myMacros.selectTextBetweenDelimiters",
        "title": "Select Text Between Delimiters",
        "category": "My Macros"
      }
    ],
    "keybindings": [
      {
        "command": "myMacros.copyTextBetweenDelimiters",
        "key": "ctrl+alt+d",
        "when": "editorTextFocus"
      },
      {
        "command": "myMacros.selectTextBetweenDelimiters",
        "key": "ctrl+alt+s",
        "when": "editorTextFocus"
      }
    ]
  }
}</code></pre>
<h3><span id="toc30">extension.tsでの登録</span></h3>
<pre><code class="language-typescript">import { copyTextBetweenDelimiters, selectTextBetweenDelimiters } from './macros/copyTextBetweenDelimiters';

export function activate(context: vscode.ExtensionContext) {
    const commands = [
        vscode.commands.registerCommand(
            'myMacros.copyTextBetweenDelimiters',
            copyTextBetweenDelimiters
        ),
        vscode.commands.registerCommand(
            'myMacros.selectTextBetweenDelimiters',
            selectTextBetweenDelimiters
        ),
        // ... 他のコマンド
    ];

    commands.forEach(command =&gt; context.subscriptions.push(command));
}</code></pre>
<h2><span id="toc31">使い方</span></h2>
<h3><span id="toc32">基本的な使い方</span></h3>
<p><strong>ステップ1：カーソルを配置</strong></p>
<p>デリミタで囲まれたテキスト内にカーソルを配置します。</p>
<pre><code class="language-javascript">const message = "ここにカーソル";
                 ↑</code></pre>
<p><strong>ステップ2：マクロ実行</strong></p>
<ul>
<li><code>Ctrl+Alt+D</code> → 選択してクリップボードにコピー</li>
<li><code>Ctrl+Alt+S</code> → 選択のみ（クリップボードは変更しない）</li>
</ul>
<p><strong>ステップ3：完了</strong></p>
<p>デリミタ内のテキストが選択（または選択＋コピー）されます。</p>
<h3><span id="toc33">コピー&貼り付け置換の使い方</span></h3>
<p><code>Ctrl+Alt+D</code>と<code>Ctrl+Alt+S</code>を組み合わせると、クリップボードを保持したまま置換できます。</p>
<pre><code class="language-javascript">const src = "コピー元のテキスト";
const dst = "ここに上書きしたい";</code></pre>
<ol>
<li><code>&quot;コピー元のテキスト&quot;</code> 内にカーソル → <code>Ctrl+Alt+D</code> でコピー</li>
<li><code>&quot;ここに上書きしたい&quot;</code> 内にカーソルを移動</li>
<li><code>Ctrl+Alt+S</code> で選択（クリップボードは変わらない）</li>
<li><code>Ctrl+V</code> で貼り付け → 置換完了！</li>
</ol>
<h3><span id="toc34">方向別の使い方</span></h3>
<h4>右方向検索</h4>
<p>開始デリミタを1文字選択（左→右）してから<code>Ctrl+Alt+D</code></p>
<pre><code class="language-plaintext">＜"あいうえお"＞
   ↑選択 ↑カーソル</code></pre>
<p>→ 右に<code>&quot;</code>を検索して<code>あいうえお</code>を選択</p>
<h4>左方向検索</h4>
<p>終了デリミタを1文字選択（右→左）してから<code>Ctrl+Alt+D</code></p>
<pre><code class="language-plaintext">＜"あいうえお"＞
   ↑カーソル ↑選択</code></pre>
<p>→ 左に<code>&quot;</code>を検索して<code>あいうえお</code>を選択</p>
<h2><span id="toc35">トラブルシューティング</span></h2>
<h3><span id="toc36">Q: デリミタが認識されない</span></h3>
<p><strong>A:</strong> 対応デリミタを確認してください</p>
<p>現在対応しているのは18種類のデリミタです。バッククォート（<code>`</code>）も対応済みです。対応していないデリミタは<code>DELIMITER_PAIRS</code>配列に追加すれば簡単に拡張できます。</p>
<h3><span id="toc37">Q: 入れ子構造で意図しない範囲が選択される</span></h3>
<p><strong>A:</strong> ネストレベルを考慮して正確にマッチングします</p>
<p>改修後のバージョンでは、括弧のネストレベルを考慮して対応する括弧を検出します。</p>
<pre><code class="language-javascript">function(a, (b, c), d)
        ↑ここにカーソル</code></pre>
<p>この場合：</p>
<ul>
<li>カーソルの左で最も近い<code>(</code>（<code>function</code>の後）を検出</li>
<li>ネストレベルをカウントしながら対応する<code>)</code>を検索</li>
<li>内側の<code>(b, c)</code>のネストを考慮して、最外側の<code>)</code>を正確に検出</li>
</ul>
<p><strong>ただし、異なる種類のデリミタの場合は最も近いものが優先されます：</strong></p>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
     ↑ここにカーソル</code></pre>
<p>この場合、<code>「～」</code>が選択されます（最も近いため）。外側の<code>&quot;～&quot;</code>を選択したい場合は、<code>&quot;</code>と<code>「</code>の間にカーソルを配置してください。</p>
<h3><span id="toc38">Q: 行全体がコピーされてしまう</span></h3>
<p><strong>A:</strong> デリミタが見つからない場合のフォールバック動作です</p>
<ul>
<li>カーソル位置の左に開始デリミタがない</li>
<li>対応する終了デリミタが右に見つからない</li>
<li>カーソル位置がデリミタの外側</li>
</ul>
<p>これらの場合、安全のため行全体をコピーします。</p>
<h3><span id="toc39">Q: 動作が遅い</span></h3>
<p><strong>A:</strong> 行内のみの検索なのでパフォーマンス問題はありません</p>
<p>1行あたりの検索は線形時間（O(n)）で、通常の行（数百文字）なら瞬時に完了します。</p>
<h2><span id="toc40">パフォーマンスについて</span></h2>
<h3><span id="toc41">計算量</span></h3>
<ul>
<li>
<p><strong>時間計算量</strong>: O(n × m)</p>
<ul>
<li>n: 行の文字数</li>
<li>m: デリミタペアの数（18個）</li>
<li>通常の行（100文字）なら約1800回の比較</li>
</ul>
</li>
<li>
<p><strong>空間計算量</strong>: O(1)</p>
<ul>
<li>固定サイズのデータ構造のみ使用</li>
</ul>
</li>
</ul>
<h3><span id="toc42">ベンチマーク（参考値）</span></h3>
<ul>
<li>100文字の行: < 1ms</li>
<li>1000文字の行: < 5ms</li>
<li>10000文字の行: < 50ms</li>
</ul>
<p><strong>実用上、全く問題ないレベルです。</strong></p>
<h2><span id="toc43">拡張アイデア</span></h2>
<h3><span id="toc44">カスタムデリミタの設定</span></h3>
<p>VSCodeの設定ファイル（settings.json）から読み込むようにすれば、ユーザー独自のデリミタにも対応可能です。</p>
<pre><code class="language-json">{
  "myMacros.customDelimiters": [
    { "start": "/*", "end": "*/" },
    { "start": "&lt;!--", "end": "--&gt;" }
  ]
}</code></pre>
<h3><span id="toc45">複数行対応</span></h3>
<p>現在は行内のみですが、開始・終了デリミタが別の行にある場合も対応できます（ただし、パフォーマンスへの配慮が必要）。</p>
<h2><span id="toc46">まとめ：キーボード1回でデリミタ内を抜き出す快適さ</span></h2>
<p>VSCodeの標準機能では手が届かなかった「デリミタ間のテキスト選択」を、TypeScriptマクロで実現しました。</p>
<p><strong>このマクロの強み：</strong></p>
<ul>
<li>1キー操作で完結（<code>Ctrl+Alt+D</code> コピー / <code>Ctrl+Alt+S</code> 選択のみ）</li>
<li>18種類のデリミタに対応（バッククォートも含む）</li>
<li>選択方向で動作を切り替え可能</li>
<li>入れ子構造でも正確に動作（ネストレベル考慮）</li>
<li>パフォーマンス問題なし</li>
<li>デリミタが見つからない場合も安全（行全体をフォールバック）</li>
</ul>
<p><strong>こんな人におすすめ：</strong></p>
<ul>
<li>コードレビューでログやJSONを頻繁に扱う</li>
<li>文字列リテラルのコピペが多い</li>
<li>マウス操作を減らしたい</li>
<li>キーボードだけで完結させたい</li>
</ul>
<p>標準のVSCodeでは「Ctrl+Shift+→」を何度も押す必要があった操作が、<strong>たった1回のキー操作</strong>で完了します。</p>
<p>「需要はないかもしれない」と思っていましたが、<strong>一度使うと手放せない便利機能</strong>です。特に大量のテキストを扱う作業では、作業効率が劇的に向上します。</p>
<p>ぜひVSCodeでの快適なテキスト編集にお役立てください！</p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発","b":"オライリージャパン","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51vjj+osAgL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4873119049","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4873119049","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"vFiVC","s":"s"});</script></p>
<div id="msmaflink-vFiVC">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc47">関連記事</span></h2>
<ul>
<li>VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-select-copy-macro/" title="VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに：テキスト編集における「範囲選択の不便さ」VSCodeで長いログファイルやドキュメントを編集していて、「この行から特定の文字列まで一気にコピーしたい」と思ったことはありませんか？通常のVSCodeでは、以下のような手順が必要です：開...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.08</div></div></div></div></a>
<ul>
<li>VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-replace-by-selection-macro/" title="VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ【テキスト編集が10倍速くなる】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ【テキスト編集が10倍速くなる】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにテキスト編集で「複数の文字列を一度に置換したい」と思ったことはありませんか？例えば、こんなシーン：変数名を複数箇所で一括変更テーブル定義のデータ型を複数列で一括更新ドキュメント内の用語統一を複数ワードで一括実施VSCodeの標準機能...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.08</div></div></div></div></a>
<ul>
<li>VSCodeで正規表現マッチを一括抽出するTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-regex-extract-macro/" title="VSCodeで「正規表現マッチ抽出」を実現するTypeScriptマクロ【ログ解析が10倍速くなる】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeで「正規表現マッチ抽出」を実現するTypeScriptマクロ【ログ解析が10倍速くなる】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにサーバーログやアプリケーションログを解析する時、こんな悩みありませんか？2024-02-08 10:00:00 INFO: Server started2024-02-08 10:01:00 ERROR: Connection fa...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.08</div></div></div></div></a>
<ul>
<li>VSCodeでパスを読み取り専用で開くTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-open-path-readonly-macro/" title="VSCodeでカーソル下のパスを開くマクロ【Office読み取り専用・関連付けアプリ・連続起動対応】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeでカーソル下のパスを開くマクロ【Office読み取り専用・関連付けアプリ・連続起動対応】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにVSCodeでコードやドキュメントを書いている時、テキスト内にパスが書かれていてそのファイルを開きたいこと、ありませんか？作業メモ.txt---設計書: C:\work\documents\設計書_v1.0.docx手順書: C:\...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.06</div></div></div></div></a>
<hr>
<p><strong>タグ:</strong> #VSCode #TypeScript #マクロ #テキスト編集 #生産性向上 #エディタ</p><p>The post <a href="https://caymezon.com/vscode-delimiter-copy-macro/">VSCodeで「デリミタ間テキスト選択コピー」を実現するTypeScriptマクロ【括弧・引用符を1キーで抜き出し】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/vscode-delimiter-copy-macro/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】</title>
		<link>https://caymezon.com/vscode-select-copy-macro/</link>
					<comments>https://caymezon.com/vscode-select-copy-macro/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 08 Feb 2026 00:27:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[VSCode]]></category>
		<category><![CDATA[エディタ]]></category>
		<category><![CDATA[マクロ]]></category>
		<category><![CDATA[生産性向上]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20101</guid>

					<description><![CDATA[<p>目次 はじめに：テキスト編集における「範囲選択の不便さ」実装した機能プリセット選択（↑↓キーで選択）直接入力も可能具体的な使用場面とメリット場面1：ログファイルの特定区間を抽出場面2：Markdownドキュメントのセクシ [&#8230;]</p>
<p>The post <a href="https://caymezon.com/vscode-select-copy-macro/">VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに：テキスト編集における「範囲選択の不便さ」</a></li><li><a href="#toc2" tabindex="0">実装した機能</a><ol><li><a href="#toc3" tabindex="0">プリセット選択（↑↓キーで選択）</a></li><li><a href="#toc4" tabindex="0">直接入力も可能</a></li></ol></li><li><a href="#toc5" tabindex="0">具体的な使用場面とメリット</a><ol><li><a href="#toc6" tabindex="0">場面1：ログファイルの特定区間を抽出</a></li><li><a href="#toc7" tabindex="0">場面2：Markdownドキュメントのセクション単位でコピー</a></li><li><a href="#toc8" tabindex="0">場面3：コード内の関数やクラスを抽出</a></li><li><a href="#toc9" tabindex="0">メリットまとめ</a></li></ol></li><li><a href="#toc10" tabindex="0">実装コード</a><ol><li><a href="#toc11" tabindex="0">コードのポイント解説</a></li></ol></li><li><a href="#toc12" tabindex="0">セットアップ方法</a><ol><li><a href="#toc13" tabindex="0">簡易手順</a></li></ol></li><li><a href="#toc14" tabindex="0">サクラエディタからの移行という視点</a></li><li><a href="#toc15" tabindex="0">まとめ：キーボードだけで完結するテキスト編集</a></li><li><a href="#toc16" tabindex="0">参考リンク</a></li><li><a href="#toc17" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに：テキスト編集における「範囲選択の不便さ」</span></h2>
<p>VSCodeで長いログファイルやドキュメントを編集していて、「この行から特定の文字列まで一気にコピーしたい」と思ったことはありませんか？</p>
<p>通常のVSCodeでは、以下のような手順が必要です：</p>
<ol>
<li>開始位置でクリック</li>
<li>スクロールして目的の行を探す</li>
<li>Shiftを押しながら終了位置をクリック</li>
<li>Ctrl+Cでコピー</li>
</ol>
<p><strong>数百行離れた箇所を選択する場合、この作業は非常に煩雑です。</strong></p>
<p>私はサクラエディタから移行してきた際、この「任意行までの一括選択・コピー」機能がなくて困っていました。以前サクラエディタ用に作成したJavaScriptマクロ（<a href="https://caymezon.com/sakura-js-line-text-copy/">任意文字を含む行まで一括範囲選択コピー</a>）の機能をVSCodeでも実現したかったのです。</p>
<p>そこで、<strong>TypeScriptでVSCode拡張機能を自作し、キーボードショートカット一発で範囲選択・コピーできる機能を実装しました。</strong></p>
<p>本記事では、実際に開発した機能とそのTypeScriptコードを紹介します。同じような悩みを持つ方の参考になれば幸いです。</p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで (Software Design plus)","b":"技術評論社","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/510GhCOD1FL._SL500_.jpg","\/41og2y1EEHL._SL500_.jpg","\/51XHb97PpFL._SL500_.jpg","\/51uDIY22bQL._SL500_.jpg","\/51PaoVK3MWL._SL500_.jpg","\/51eG7JBoavL._SL500_.jpg","\/51CDCo8FmJL._SL500_.jpg","\/41JLTXb+tsL._SL500_.jpg","\/51Hsv39e7IL._SL500_.jpg","\/41PTe+TqLEL._SL500_.jpg","\/51TUxdoXjrL._SL500_.jpg","\/51AkZEJWGhL._SL500_.jpg","\/51paP7D5R5L._SL500_.jpg","\/41lJtbpaQvL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4297127474","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4297127474","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"OaDLa","s":"s"});</script></p>
<div id="msmaflink-OaDLa">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">実装した機能</span></h2>
<p><strong>Ctrl+Alt+C</strong>: 現在行から指定位置までコピー</p>
<p>これが本マクロの核となる機能です。ダイアログが開き、以下の方法で終了位置を決定できます：</p>
<h3><span id="toc3">プリセット選択（↑↓キーで選択）</span></h3>
<ul>
<li><strong>空行</strong>: 次の空行の1つ前まで</li>
<li><strong>EOF</strong>: ファイル末尾まで</li>
<li><strong>▲</strong>: 「▲」を含む行の1つ前まで</li>
<li><strong>▲▲▲</strong>: 「▲▲▲」を含む行の1つ前まで</li>
<li><strong>```</strong>: コードブロック終端の1つ前まで</li>
<li><strong>---</strong>: 区切り線の1つ前まで</li>
</ul>
<h3><span id="toc4">直接入力も可能</span></h3>
<p>プリセットを選ばずに、そのまま文字列を入力してEnterでもOK。例えば「TODO」と入力すれば、TODOを含む行の1つ前までコピーされます。</p>
<h2><span id="toc5">具体的な使用場面とメリット</span></h2>
<h3><span id="toc6">場面1：ログファイルの特定区間を抽出</span></h3>
<p>大量のログファイルから、<code>START</code>から<code>END</code>までのセクションだけを抽出したい場合：</p>
<pre><code class="language-plaintext">2026-02-08 10:00:00 INFO: Application started
2026-02-08 10:00:01 DEBUG: Loading configuration
START
2026-02-08 10:00:05 ERROR: Connection timeout
2026-02-08 10:00:06 WARN: Retrying connection
... (数百行のログ)
END
2026-02-08 11:00:00 INFO: Process completed</code></pre>
<p><strong>操作手順：</strong></p>
<ol>
<li><code>START</code>の行にカーソルを置く</li>
<li><code>Ctrl+Alt+C</code>を押す</li>
<li>ダイアログに<code>END</code>と直接入力してEnter</li>
<li>→ 一瞬で<code>START</code>から<code>END</code>の1行前までがコピーされる（ENDは含まない）</li>
</ol>
<p><strong>従来の方法だと</strong>、スクロールしながらShiftクリックで選択する必要があり、数百行離れていると非常に面倒でした。</p>
<h3><span id="toc7">場面2：Markdownドキュメントのセクション単位でコピー</span></h3>
<p>Markdownファイルで特定のセクションだけをコピーしたい場合：</p>
<pre><code class="language-markdown">## はじめに

本記事では...

## インストール手順

以下の手順で...
... (長い説明)

## 設定方法

設定ファイルに...</code></pre>
<p>見出しの行で<code>Ctrl+Alt+C</code>を押し、プリセットから「空行」を選択すれば、次の空行（セクションの区切り）までが自動コピーされます。</p>
<h3><span id="toc8">場面3：コード内の関数やクラスを抽出</span></h3>
<p>JavaScriptやPythonのコードで、特定の関数だけを別ファイルにコピーしたい場合：</p>
<pre><code class="language-typescript">export async function processData() {
    const editor = vscode.window.activeTextEditor;
    // ... 処理内容 (50行)
}</code></pre>
<p>関数の先頭行で<code>Ctrl+Alt+C</code>を押し、「空行」を選択すれば、次の空行（関数の終わり）まで一括コピーできます。</p>
<h3><span id="toc9">メリットまとめ</span></h3>
<ul>
<li><strong>スクロール不要</strong>: 目的の文字列を入力するだけ</li>
<li><strong>正確</strong>: クリック位置のミスがない</li>
<li><strong>高速</strong>: キーボードだけで完結</li>
<li><strong>汎用性</strong>: 任意の文字列を指定可能</li>
<li><strong>柔軟性</strong>: プリセット選択と直接入力の両対応</li>
</ul>
<h2><span id="toc10">実装コード</span></h2>
<p>実際のTypeScriptコードを紹介します。<code>copyToSpecifiedLine.ts</code>ファイルに以下の内容を実装しました。</p>
<pre><code class="language-typescript">import * as vscode from 'vscode';

/**
 * プリセット検索パターン
 */
const PRESET_PATTERNS = [
    { label: '空行', value: 'EMPTY_LINE', description: '次の空行まで' },
    { label: 'EOF', value: 'EOF', description: 'ファイル末尾まで' },
    { label: '▲', value: '▲', description: '▲が含まれる行の前まで' },
    { label: '▲▲▲', value: '▲▲▲', description: '▲▲▲が含まれる行の前まで' },
    { label: '```', value: '```', description: 'コードブロック終端の前まで' },
    { label: '---', value: '---', description: '区切り線の前まで' }
];

/**
 * 現在行から指定行までをコピー
 */
export async function copyToSpecifiedLine() {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        vscode.window.showWarningMessage('アクティブなエディタがありません');
        return;
    }

    const document = editor.document;
    const currentLine = editor.selection.active.line;
    
    // パターン選択ダイアログ
    const pattern = await showPatternDialog();
    if (pattern === null) {
        return; // キャンセル
    }
    
    // 終了行を検索
    const endLine = await findEndLine(document, currentLine, pattern);
    if (endLine === null) {
        return; // 見つからない/エラー
    }
    
    // 範囲選択（改行を含む）
    const startPos = new vscode.Position(currentLine, 0);
    // 改行を含めるため、次の行の先頭を終了位置にする（最終行の場合は行末）
    const endPos = endLine < document.lineCount - 1
        ? new vscode.Position(endLine + 1, 0)
        : new vscode.Position(endLine, document.lineAt(endLine).text.length);
    const range = new vscode.Range(startPos, endPos);
    
    // 選択
    editor.selection = new vscode.Selection(range.start, range.end);
    
    // コピー
    await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
    
    // 選択状態を維持（移動しない）
}

/**
 * パターン選択ダイアログを表示（直接入力も可能）
 * @returns 選択されたパターン文字列、またはnull（キャンセル時）
 */
async function showPatternDialog(): Promise<string | null> {
    const quickPick = vscode.window.createQuickPick();
    quickPick.items = PRESET_PATTERNS;
    quickPick.placeholder = '終了位置を選択または直接入力してください';
    quickPick.ignoreFocusOut = true;
    
    return new Promise((resolve) => {
        quickPick.onDidAccept(() => {
            const selected = quickPick.selectedItems[0];
            const inputValue = quickPick.value.trim();
            
            // 選択肢を選んだ場合
            if (selected) {
                const pattern = PRESET_PATTERNS.find(p => p.label === selected.label);
                resolve(pattern?.value || null);
                quickPick.hide();
            }
            // 直接入力した場合（選択肢を選ばずにEnter）
            else if (inputValue) {
                resolve(inputValue);
                quickPick.hide();
            } else {
                // 何も入力せずにEnter（キャンセル扱い）
                resolve(null);
                quickPick.hide();
            }
        });
        
        quickPick.onDidHide(() => {
            resolve(null);
            quickPick.dispose();
        });
        
        quickPick.show();
    });
}

/**
 * 終了行を検索
 * @param document ドキュメント
 * @param startLine 開始行（0-based）
 * @param pattern 検索パターン
 * @returns 終了行番号（0-based）、またはnull（見つからない/エラー）
 */
async function findEndLine(
    document: vscode.TextDocument,
    startLine: number,
    pattern: string
): Promise<number | null> {
    const lastLine = document.lineCount - 1;
    
    // EOF の場合
    if (pattern === 'EOF') {
        return lastLine;
    }
    
    // 空行の場合
    if (pattern === 'EMPTY_LINE') {
        for (let i = startLine + 1; i <= lastLine; i++) {
            const line = document.lineAt(i);
            if (line.isEmptyOrWhitespace) {
                // 空行の1つ前の行を返す
                return i - 1;
            }
        }
        
        // 空行が見つからない場合は最終行
        vscode.window.showInformationMessage('空行が見つからないため、ファイル末尾まで選択します');
        return lastLine;
    }
    
    // 文字列検索（指定文字列がある行の1つ前まで）
    for (let i = startLine + 1; i <= lastLine; i++) {
        const lineText = document.lineAt(i).text;
        if (lineText.includes(pattern)) {
            // 指定文字列がある行の1つ前を返す
            if (i - 1 <= startLine) {
                vscode.window.showWarningMessage('指定文字列が次の行にあるため、選択できません');
                return null;
            }
            return i - 1;
        }
    }
    
    // 見つからない場合は最終行
    vscode.window.showInformationMessage(`「${pattern}」が見つからないため、ファイル末尾まで選択します`);
    return lastLine;
}</code></pre>
<h3><span id="toc11">コードのポイント解説</span></h3>
<h4>1. QuickPickによる柔軟な入力</h4>
<pre><code class="language-typescript">const quickPick = vscode.window.createQuickPick();
quickPick.items = PRESET_PATTERNS;
quickPick.placeholder = '終了位置を選択または直接入力してください';</code></pre>
<p><code>createQuickPick</code>を使うことで、プリセットから選択することも、直接文字列を入力することも可能になります。</p>
<h4>2. プリセットと直接入力の両対応</h4>
<pre><code class="language-typescript">quickPick.onDidAccept(() => {
    const selected = quickPick.selectedItems[0];
    const inputValue = quickPick.value.trim();
    
    if (selected) {
        // プリセット選択
        resolve(pattern?.value || null);
    } else if (inputValue) {
        // 直接入力
        resolve(inputValue);
    }
});</code></pre>
<p>ユーザーの操作に応じて、適切な値を返します。</p>
<h4>3. 空行検出のロジック</h4>
<pre><code class="language-typescript">if (line.isEmptyOrWhitespace) {
    return i - 1;
}</code></pre>
<p><code>isEmptyOrWhitespace</code>プロパティを使うことで、改行のみまたは空白のみの行を正確に判定できます。指定文字列自体は含まないため、1つ前の行を返します。</p>
<h4>4. 改行を含む選択</h4>
<pre><code class="language-typescript">const endPos = endLine < document.lineCount - 1
    ? new vscode.Position(endLine + 1, 0)  // 次の行の先頭（改行含む）
    : new vscode.Position(endLine, document.lineAt(endLine).text.length);</code></pre>
<p>選択範囲に改行を含めることで、貼り付け時に自動的に改行が入ります。</p>
<h2><span id="toc12">セットアップ方法</span></h2>
<p>この機能を使うには、VSCode拡張機能として開発する必要があります。詳細な手順は以下の関連記事を参照してください：</p>
<ul>
<li>VSCodeのTypeScriptマクロ開発ガイド</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-typescript-macro-development-guide/" title="VSCode TypeScriptマクロ開発環境の完全ガイド【セットアップから運用まで】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCode TypeScriptマクロ開発環境の完全ガイド【セットアップから運用まで】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにVSCodeでカスタムマクロを作成したいけど、どうやって開発環境を構築すればいいか分からない。そんな悩みを持つ方に向けて、TypeScriptでVSCode拡張機能を開発する環境の構築から、実際にマクロを作成して使えるようにするまで...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.25</div></div></div></div></a>
<ul>
<li>サクラエディタからVSCodeへのマクロ移行方法</li>
</ul>

<a rel="noopener" href="https://caymezon.com/sakura-to-vscode-macro-migration/" title="サクラエディタからVSCodeへマクロ移行！快適開発環境の構築記録" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">サクラエディタからVSCodeへマクロ移行！快適開発環境の構築記録</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに長年愛用してきたサクラエディタのマクロ機能。便利なJavaScript/VBSマクロを多数作成して日常業務で活用してきましたが、最近のAWS開発やブログ執筆でVSCodeを使う機会が増えてきました。「VSCodeでもサクラエディタの...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.25</div></div></div></div></a>
<h3><span id="toc13">簡易手順</span></h3>
<ol>
<li>VSCode拡張機能プロジェクトを作成</li>
<li>上記TypeScriptコードを<code>src/macros/copyToSpecifiedLine.ts</code>に配置</li>
<li><code>package.json</code>にコマンドとキーバインディングを登録</li>
</ol>
<pre><code class="language-json">{
  "contributes": {
    "commands": [
      {
        "command": "myMacros.copyToSpecifiedLine",
        "title": "Copy to Specified Line"
      }
    ],
    "keybindings": [
      {
        "command": "myMacros.copyToSpecifiedLine",
        "key": "ctrl+alt+c",
        "when": "editorTextFocus"
      }
    ]
  }
}</code></pre>
<ol start="4">
<li>ビルドしてVSIXファイルをインストール</li>
</ol>
<pre><code class="language-bash">npm run compile
vsce package
code --install-extension my-macros-0.0.10.vsix</code></pre>
<h2><span id="toc14">サクラエディタからの移行という視点</span></h2>
<p>かつてサクラエディタで実装していた機能（<a href="https://caymezon.com/sakura-js-line-text-copy/">任意文字を含む行まで一括範囲選択コピー</a>）を、VSCodeでも実現できました。</p>
<p>サクラエディタのJavaScriptマクロでは以下のようなコードでした：</p>
<pre><code class="language-javascript">// サクラエディタ版（抜粋）
var userInput = Editor.InputBox("終了位置を指定してください", "…");
for (var y = start; y <= last; y++) {
    var s = getLineBySelect(y);
    if (s.indexOf(marker) >= 0) return y;
}</code></pre>
<p>VSCodeでは以下のように書き直せます：</p>
<pre><code class="language-typescript">// VSCode版
const quickPick = vscode.window.createQuickPick();
quickPick.items = PRESET_PATTERNS;
// プリセット選択 or 直接入力

for (let i = startLine + 1; i <= lastLine; i++) {
    const lineText = document.lineAt(i).text;
    if (lineText.includes(pattern)) {
        return i - 1;  // 指定行の1つ前
    }
}</code></pre>
<p><strong>TypeScriptの方が型安全で、VSCode APIも充実しているため、より堅牢な実装が可能です。</strong></p>
<h2><span id="toc15">まとめ：キーボードだけで完結するテキスト編集</span></h2>
<p>今回実装した機能により、以下が実現できました：</p>
<ul>
<li><strong>Ctrl+Alt+C</strong>: プリセット選択または任意の文字列まで選択・コピー</li>
</ul>
<p>この機能は、以下のような作業で特に威力を発揮します：</p>
<ol>
<li><strong>ログファイル解析</strong>: 特定のセクションだけを抽出</li>
<li><strong>ドキュメント編集</strong>: Markdownのセクション単位でコピー</li>
<li><strong>コードレビュー</strong>: 関数やクラス単位で抽出</li>
<li><strong>データ整形</strong>: 区切り文字で範囲指定して一括処理</li>
</ol>
<p>「需要はないかもしれない」と思っていましたが、<strong>一度使うと手放せない便利機能</strong>です。特に大量のテキストを扱う作業では、作業効率が劇的に向上します。</p>
<p>同じような悩みを持つ方は、ぜひ試してみてください。TypeScriptでVSCodeマクロを書く楽しさも味わえるはずです。</p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発","b":"オライリージャパン","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51vjj+osAgL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4873119049","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4873119049","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"vFiVC","s":"s"});</script></p>
<div id="msmaflink-vFiVC">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc16">参考リンク</span></h2>
<ul>
<li>サクラエディタ版の元記事: [任意文字を含む行まで一括範囲選択コピー]</li>
</ul>

<a rel="noopener" href="https://caymezon.com/sakura-js-line-text-copy/" title="【サクラエディタ】任意文字を含む行まで一括範囲選択コピー【操作画像あり】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2019/09/line-text-copy-eyecatch-160x90.gif" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2019/09/line-text-copy-eyecatch-160x90.gif 160w, https://caymezon.com/wp-content/uploads/2019/09/line-text-copy-eyecatch-300x169.gif 300w, https://caymezon.com/wp-content/uploads/2019/09/line-text-copy-eyecatch-768x432.gif 768w, https://caymezon.com/wp-content/uploads/2019/09/line-text-copy-eyecatch-1024x576.gif 1024w, https://caymezon.com/wp-content/uploads/2019/09/line-text-copy-eyecatch-120x68.gif 120w, https://caymezon.com/wp-content/uploads/2019/09/line-text-copy-eyecatch-320x180.gif 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【サクラエディタ】任意文字を含む行まで一括範囲選択コピー【操作画像あり】</div><div class="blogcard-snippet internal-blogcard-snippet">サクラエディタで複数行の範囲選択テキストを一括で超簡単にコピーするマクロをJavaScriptで作ってみました。わざわざマウスを使ってある程度まとまった行を選択する操作、めんどくさくないですか？頻繁にコピー作業する人にはきっと役に立つと思い...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2019.09.08</div></div></div></div></a>
<h2><span id="toc17">関連記事</span></h2>
<ul>
<li>サクラエディタからVSCodeへのマクロ移行完全ガイド</li>
</ul>

<a rel="noopener" href="https://caymezon.com/sakura-to-vscode-macro-migration/" title="サクラエディタからVSCodeへマクロ移行！快適開発環境の構築記録" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">サクラエディタからVSCodeへマクロ移行！快適開発環境の構築記録</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに長年愛用してきたサクラエディタのマクロ機能。便利なJavaScript/VBSマクロを多数作成して日常業務で活用してきましたが、最近のAWS開発やブログ執筆でVSCodeを使う機会が増えてきました。「VSCodeでもサクラエディタの...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.25</div></div></div></div></a>
<ul>
<li>VSCodeでTypeScriptマクロ開発を始めるための完全ガイド</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-typescript-macro-development-guide/" title="VSCode TypeScriptマクロ開発環境の完全ガイド【セットアップから運用まで】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCode TypeScriptマクロ開発環境の完全ガイド【セットアップから運用まで】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにVSCodeでカスタムマクロを作成したいけど、どうやって開発環境を構築すればいいか分からない。そんな悩みを持つ方に向けて、TypeScriptでVSCode拡張機能を開発する環境の構築から、実際にマクロを作成して使えるようにするまで...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.25</div></div></div></div></a><p>The post <a href="https://caymezon.com/vscode-select-copy-macro/">VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/vscode-select-copy-macro/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
