Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17055] ファイルの概要

このコミットは、misc/notepadplus/functionList.xml ファイルに対する変更です。このファイルは、Notepad++ エディタの「Function List」機能で使用される設定ファイルであり、Go 言語の関数やメソッドを正しく認識し、一覧表示するための正規表現が定義されています。この変更の目的は、既存の正規表現を簡素化し、より効率的で保守しやすいものにすることです。

コミット

このコミットは、Notepad++ の Go 言語用 Function List の正規表現を簡素化することを目的としています。具体的には、関数名とクラス名(Go の場合はレシーバの型)を抽出するための正規表現が修正され、冗長なパターンが削除されています。これにより、Notepad++ が Go コードの構造をより効率的に解析できるようになります。

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/7583c14be7a4d3c2289c536148bc65957c41f3fc

元コミット内容

commit 7583c14be7a4d3c2289c536148bc65957c41f3fc
Author: ChaiShushan <chaishushan@gmail.com>
Date:   Tue Aug 6 07:57:51 2013 -0700

    misc/notepadplus: simplify Function List regex
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/12508043

変更の背景

Notepad++ の Function List 機能は、ソースコード内の関数やメソッドを解析し、サイドバーに一覧表示することで、コードのナビゲーションを容易にします。Go 言語のサポートを改善するためには、Go の関数宣言(通常の関数とレシーバを持つメソッドの両方)を正確に識別する正規表現が必要です。

このコミット以前の functionList.xml には、Go の関数を識別するための正規表現が含まれていましたが、それらは冗長であったり、最適化の余地があったと考えられます。正規表現の簡素化は、以下の利点をもたらします。

  1. パフォーマンスの向上: よりシンプルな正規表現は、解析エンジンがコードをスキャンする際の処理時間を短縮する可能性があります。
  2. 保守性の向上: 複雑な正規表現は理解しにくく、将来の変更やデバッグが困難になります。簡素化により、設定ファイルの保守が容易になります。
  3. 正確性の向上: 冗長なパターンを削除することで、意図しないマッチングを防ぎ、より正確な関数リストの生成に貢献する可能性があります。

この変更は、Notepad++ を Go 開発環境として使用しているユーザーにとって、よりスムーズなコードナビゲーション体験を提供することを目的としています。

前提知識の解説

Notepad++ Function List

Notepad++ は、Windows 環境で広く利用されている高機能なテキストエディタです。その主要な機能の一つに「Function List」があります。これは、現在開いているファイル内の関数、メソッド、クラスなどの定義を解析し、ツリービュー形式で一覧表示する機能です。ユーザーはこのリストをクリックすることで、コード内の対応する定義に素早くジャンプできます。

Function List は、各プログラミング言語の構文解析に正規表現を使用します。functionList.xml ファイルは、これらの正規表現を定義するための設定ファイルであり、Notepad++ がどのパターンを関数として認識するかを決定します。

正規表現 (Regular Expression)

正規表現は、文字列のパターンを記述するための強力なツールです。特定の文字の並び、繰り返し、選択肢などを簡潔に表現できます。プログラミング言語における文字列の検索、置換、検証など、幅広い用途で利用されます。

このコミットで変更されている正規表現の主要な要素は以下の通りです。

  • ^: 行の先頭にマッチします。
  • func: リテラル文字列 "func" にマッチします。
  • \s: 任意の空白文字(スペース、タブ、改行など)にマッチします。
  • \w: 任意の単語文字(英数字とアンダースコア [a-zA-Z0-9_])にマッチします。[\w] と同じ意味です。
  • +: 直前の要素が1回以上繰り返されることにマッチします。
  • *: 直前の要素が0回以上繰り返されることにマッチします。
  • ?: 直前の要素が0回または1回出現することにマッチします(オプション)。
  • |: 論理 OR を表し、左右のいずれかのパターンにマッチします。
  • \( \): リテラルの括弧 ( ) にマッチします。正規表現の特殊文字であるためエスケープが必要です。

Go 言語の関数とメソッドの構文

Go 言語では、関数とメソッドは以下のような構文で宣言されます。

  1. 通常の関数:

    func functionName(parameters) (returnValues) {
        // ...
    }
    

    例: func main(), func add(a, b int) int

  2. メソッド (レシーバを持つ関数):

    func (receiverName receiverType) methodName(parameters) (returnValues) {
        // ...
    }
    

    例: func (u *User) GetName() string, func (s MyStruct) String() string

Notepad++ の Function List は、これらの宣言パターンを正規表現で捉え、関数名 (functionName または methodName) と、メソッドの場合はレシーバの型 (receiverType) を抽出する必要があります。functionList.xml<functionName> タグ内の nameExpr は関数名を、<className> タグ内の nameExpr はレシーバの型を抽出するために使用されます。

技術的詳細

このコミットの技術的詳細は、functionList.xml 内の正規表現の変更に集約されます。主な変更点は、mainExpr<functionName> 内の nameExpr、および <className> 内の nameExpr の簡素化です。

mainExpr の変更

mainExpr は、Notepad++ が関数宣言の開始を識別するための主要な正規表現です。

  • 変更前:
    mainExpr="(^func\s+[\w]+)|(^func\s*\(\s*[\w]+\s+\*?\s*[\w]+\s*\)\s*[\w]+)"
    
  • 変更後:
    mainExpr="(^func\s+\w+)|(^func\s*\(\s*\w+\s*\*?\s*\w+\s*\)\s*\w+)"
    

変更点は [\w]\w に置き換えられたことです。[\w]\w はどちらも「単語文字」(英数字とアンダースコア)にマッチする正規表現のショートハンドであり、機能的には同じです。この変更は、おそらく一貫性のため、またはわずかなパフォーマンス最適化のためになされたと考えられます。

この正規表現は、以下の2つのパターンを OR (|) で結合しています。

  1. ^func\s+\w+: 行頭の func に続き、1つ以上の空白文字と1つ以上の単語文字(関数名)が続くパターン。例: func main
  2. ^func\s*\(\s*\w+\s*\*?\s*\w+\s*\)\s*\w+: 行頭の func に続き、レシーバの宣言 (receiverName receiverType) と、その後にメソッド名が続くパターン。例: func (r *MyType) MyMethod

<functionName> 内の nameExpr の変更

<functionName> セクションは、mainExpr で識別された関数宣言の中から、実際の関数名を抽出するための正規表現を定義します。

  • 変更前:
    <functionName>
        <nameExpr expr="(((func)[\s][\w]+)|(\(\s*[\w]+\s+\*?\s*[\\w]+\s*\\)\s*[\w]+))"/>
        <nameExpr expr="(((func)[\s][\w]+)|(\)\s*[\w]+))"/>
        <nameExpr expr="(([\\s][\\w]+)|(\\)\s*[\\w]+))"/>
        <nameExpr expr="[\\w]+"/>
    </functionName>
    
  • 変更後:
    <functionName>
        <nameExpr expr="((func\s+\w+)|(\)\s*\w+))"/>
        <nameExpr expr="((\s+\w+)|(\)\s*\w+))"/>
        <nameExpr expr="\w+"/>
    </functionName>
    

変更前は4つの nameExpr がありましたが、変更後は3つに減り、それぞれの正規表現も簡素化されています。

  • [\s]\s に、[\w]\w に変更されています。
  • 冗長なグループ化 ((func)[\s][\w]+)(func\s+\w+) に簡素化されています。
  • 特に、レシーバを持つメソッドの関数名(メソッド名)を抽出する部分で、より簡潔なパターンが採用されています。例えば、(\)\s*\w+) は、閉じ括弧 ) の後に空白と単語文字(メソッド名)が続くパターンにマッチします。

<className> 内の nameExpr の変更

<className> セクションは、レシーバを持つメソッドのレシーバの型を抽出するための正規表現を定義します。Notepad++ の Function List では、これを「クラス名」として表示します。

  • 変更前:
    <className>
        <nameExpr expr="\(\s*[\w]+\s+\*?\s*[\w]+\s*\)\s*[\w]+"/>
        <nameExpr expr="\(\s*[\w]+\s+\*?\s*[\w]+\s*\)"/>
        <nameExpr expr="[\w]+\s+\*?\s*[\w]+\s*\)"/>
        <nameExpr expr="\*?\s*[\w]+\s*\)"/>
        <nameExpr expr="[\w]+\s*\)"/>
        <nameExpr expr="[\w]+"/>
    </className>
    
  • 変更後:
    <className>
        <nameExpr expr="\w+\s*\)"/>
        <nameExpr expr="\w+"/>
    </className>
    

変更前は6つの nameExpr がありましたが、変更後は2つに大幅に減り、非常に簡潔になっています。

  • [\w]\w に変更されています。
  • レシーバの型を抽出する際に、より直接的なパターンが使用されています。例えば、\w+\s*\) は、単語文字(型名)の後に空白と閉じ括弧が続くパターンにマッチします。これは、func (r *MyType)*MyTypeMyType の部分を効率的に抽出することを意図しています。

これらの変更は全体として、Notepad++ が Go の関数とメソッドの構造を解析する際の正規表現の複雑さを軽減し、より堅牢で効率的な解析を可能にすることを目指しています。

コアとなるコードの変更箇所

--- a/misc/notepadplus/functionList.xml
+++ b/misc/notepadplus/functionList.xml
@@ -7,21 +7,16 @@
 		<!-- <parsers> -->
 			<parser id="go" displayName="Go" commentExpr="((/\*.*?\*)/|(//.*?$))">
 				<function
-				    mainExpr="(^func\s+[\w]+)|(^func\s*\(\s*[\w]+\s+\*?\s*[\w]+\s*\)\s*[\w]+)"
+				    mainExpr="(^func\s+\w+)|(^func\s*\(\s*\w+\s*\*?\s*\w+\s*\)\s*\w+)"
 				    displayMode="$className->$functionName">
 					<functionName>
-						<nameExpr expr="(((func)[\\s][\\w]+)|(\\(\s*[\\w]+\s+\\*?\\s*[\\w]+\s*\\)\\s*[\\w]+))"/>
-						<nameExpr expr="(((func)[\\s][\\w]+)|(\\)\s*[\\w]+))"/>
-						<nameExpr expr="(([\\s][\\w]+)|(\\)\s*[\\w]+))"/>
-						<nameExpr expr="[\\w]+"/>
+						<nameExpr expr="((func\s+\w+)|(\)\s*\w+))"/>
+						<nameExpr expr="((\s+\w+)|(\)\s*\w+))"/>
+						<nameExpr expr="\w+"/>
 					</functionName>
 					<className>
-						<nameExpr expr="\\(\s*[\\w]+\s+\\*?\\s*[\\w]+\s*\\)\\s*[\\w]+"/>
-						<nameExpr expr="\\(\s*[\\w]+\s+\\*?\\s*[\\w]+\s*\\)"/>
-						<nameExpr expr="[\\w]+\s+\\*?\\s*[\\w]+\s*\\)"/>
-						<nameExpr expr="\\*?\\s*[\\w]+\s*\\)"/>
-						<nameExpr expr="[\\w]+\s*\\)"/>
-						<nameExpr expr="[\\w]+"/>
+						<nameExpr expr="\w+\s*\)"/>
+						<nameExpr expr="\w+"/>
 					</className>
 				</function>
 			</parser>

コアとなるコードの解説

このコミットは、misc/notepadplus/functionList.xml ファイル内の Go 言語の関数リスト解析に関する正規表現を修正しています。

  1. mainExpr の変更:

    • mainExpr は、Notepad++ が Go の関数宣言を識別するための主要な正規表現です。
    • 変更前は [\w] を使用していましたが、変更後は \w に置き換えられています。これらは機能的に同じですが、\w の方がより簡潔な表記です。この変更は、正規表現の可読性を向上させ、わずかながらパフォーマンスの最適化に寄与する可能性があります。
  2. <functionName> 内の nameExpr の変更:

    • このセクションは、関数宣言から関数名(またはメソッド名)を抽出するための正規表現を定義します。
    • 変更前は4つの nameExpr がありましたが、変更後は3つに削減されています。
    • それぞれの正規表現も簡素化され、冗長なパターンが削除されています。例えば、(((func)[\s][\w]+)|(\(\s*[\w]+\s+\*?\s*[\w]+\s*\\)\s*[\w]+)) のような複雑なパターンが、より直接的な ((func\s+\w+)|(\)\s*\w+)) に置き換えられています。これにより、関数名の抽出がより効率的かつ正確に行われるようになります。特に、レシーバを持つメソッドのメソッド名(例: func (r *MyType) MyMethodMyMethod)を抽出する際のパターンが改善されています。
  3. <className> 内の nameExpr の変更:

    • このセクションは、レシーバを持つメソッドのレシーバの型を抽出するための正規表現を定義します。Notepad++ ではこれを「クラス名」として表示します。
    • 変更前は6つの nameExpr がありましたが、変更後はわずか2つに大幅に削減されています。
    • 例えば、\(\s*[\w]+\s+\*?\s*[\w]+\s*\)\s*[\w]+ のような非常に複雑なパターンが削除され、\w+\s*\)\w+ のような非常に簡潔なパターンに置き換えられています。これにより、レシーバの型(例: func (r *MyType)*MyTypeMyType)の抽出が大幅に簡素化され、効率が向上します。

全体として、このコミットは、Notepad++ の Go 言語サポートにおける正規表現の複雑さを軽減し、よりクリーンで効率的なコード解析を実現することを目的としています。これにより、Notepad++ の Function List が Go コードをより正確かつ迅速に解析できるようになり、開発者の生産性向上に貢献します。

関連リンク

参考にした情報源リンク

  • Go 言語の公式ドキュメント (上記「関連リンク」に記載)
  • 正規表現に関する一般的な情報源 (例: MDN Web Docs の正規表現ガイドなど)
  • Notepad++ の Function List 機能に関する情報 (上記「関連リンク」に記載)
  • コミットメッセージと diff の内容
  • Go 言語の構文に関する一般的な知識
  • 正規表現の構文に関する一般的な知識
  • Notepad++ の functionList.xml の構造に関する一般的な知識